Skip to content

feat(experiment): create and delete developer sandboxes#389

Merged
vegeris merged 23 commits intomainfrom
evegeris-sandbox-integration-create-delete
Mar 19, 2026
Merged

feat(experiment): create and delete developer sandboxes#389
vegeris merged 23 commits intomainfrom
evegeris-sandbox-integration-create-delete

Conversation

@vegeris
Copy link
Contributor

@vegeris vegeris commented Mar 11, 2026

Changelog

Experimental Feature: --experiment sandboxes

We're adding support for managing Slack developer sandboxes from within the CLI. We now allow one to create or delete a sandbox from the CLI.

  • sandbox create allows you to create a new developer sandbox.
  • sandbox delete allows you to delete an existing developer sandbox.

Summary

This PR adds sandbox create and sandbox delete commands, which allow one to create or delete a sandbox from the CLI.

Follow up to #379

Testing

Try out the commands:

% hermes sandbox create --experiment=sandboxes --name "my-test-box" --password "secretPassword"

% hermes sandbox delete --experiment=sandboxes --sandbox-id E012345

Requirements

@vegeris vegeris added the semver:patch Use on pull requests to describe the release version increment label Mar 11, 2026
@vegeris vegeris force-pushed the evegeris-sandbox-integration-create-delete branch 5 times, most recently from 6a724f1 to 37c62fb Compare March 11, 2026 18:38
@codecov
Copy link

codecov bot commented Mar 11, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 48 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.93%. Comparing base (8b31c6a) to head (b5de063).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
cmd/sandbox/create.go 84.66% 20 Missing and 5 partials ⚠️
cmd/sandbox/delete.go 73.52% 14 Missing and 4 partials ⚠️
internal/api/sandbox.go 95.83% 1 Missing and 1 partial ⚠️
internal/style/style.go 0.00% 2 Missing ⚠️
cmd/sandbox/sandbox.go 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #389      +/-   ##
==========================================
+ Coverage   68.62%   68.93%   +0.30%     
==========================================
  Files         218      220       +2     
  Lines       18162    18446     +284     
==========================================
+ Hits        12464    12716     +252     
- Misses       4538     4558      +20     
- Partials     1160     1172      +12     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@vegeris vegeris force-pushed the evegeris-sandbox-integration-create-delete branch 2 times, most recently from 98ecc15 to f200970 Compare March 11, 2026 23:43
@vegeris vegeris force-pushed the evegeris-sandbox-integration-create-delete branch from f200970 to cea2bcd Compare March 12, 2026 18:56
@vegeris vegeris marked this pull request as ready for review March 12, 2026 19:00
@vegeris vegeris requested a review from a team as a code owner March 12, 2026 19:00
},
}))
clients.IO.PrintInfo(ctx, false, "Manage this sandbox from the CLI or visit\n%s", style.Secondary("https://api.slack.com/developer-program/sandboxes"))
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preview:

% hermes sandbox create --experiment=sandboxes --name "EV test box 7245"  --password "jhsdjdkhfkdfgkgd"

🏖️  Sandbox Created
   Team ID: E0197Q6CTV1
   URL: https://ev-test-box-7245.enterprise.dev.slack.com/

Manage this sandbox from the CLI or visit
https://api.slack.com/developer-program/sandboxes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Excellent formatting choice!

}

return nil
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preview:

% hermes sandbox delete --experiment=sandboxes --sandbox-id E0196ATAVGT
Choose a Slack team where your email address matches your Slack developer account
? Select a team for authentication slackforceorg E014LMDF01H

⚠️  Danger zone
   Sandbox (E0196ATAVGT) and all of its data will be permanently deleted
   This cannot be undone

? Are you sure you want to delete the sandbox? Yes

✅ Sandbox deleted
   Sandbox E0196ATAVGT has been permanently deleted

🏖️  Developer Sandboxes
   Owned by Slack developer account ev@mail.com

  EV test box 8274368 (E0123456)
    URL: https://ev-test-box-29378.slack.com
    Status: ACTIVE
    Created: 2026-03-12
    Expires: 2026-09-12

Learn more at https://docs.slack.dev/tools/developer-sandboxes

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫧 thought: This is solid! I'm optimistic that a conclusion of the charm experiment might let us hide selections and warnings earlier for outputs that are focused on the result, but nothing to think about in this PR!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Excellent formatting choice!

@vegeris vegeris force-pushed the evegeris-sandbox-integration-create-delete branch from b23fbe4 to a35fbc3 Compare March 12, 2026 19:09
Copy link
Member

@zimeg zimeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vegeris LGTM! Thanks for bringing a complete sandbox experiment to scripting. I'm excited for these options 🌈 ✨

A few comments that follow are quibbles to implementation but nothing that ought block this from merging. It might be nice to add more tests to API methods, but we can explore some of this in future changes of course 🚢 💨

// Sandbox represents a Slack Developer Sandbox
type Sandbox struct {
DateArchived int64 `json:"date_archived"` // When the developer sandbox is or will be archived, as epoch seconds
DateCreated int64 `json:"date_created"` // When the developer sandbox was created, as epoch seconds
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌟 praise: To kind epoch!

}

return nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫧 thought: This is solid! I'm optimistic that a conclusion of the charm experiment might let us hide selections and warnings earlier for outputs that are focused on the result, but nothing to think about in this PR!

Comment on lines +74 to +79
if err := cmd.MarkFlagRequired("name"); err != nil {
panic(err)
}
if err := cmd.MarkFlagRequired("password"); err != nil {
panic(err)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏁 issue(non-blocking): We might want prompt alternatives for required flags but no blocker for this PR!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and added those prompts 👀

}

cmd.Flags().StringVar(&createCmdFlags.name, "name", "", "Organization name for the new sandbox")
cmd.Flags().StringVar(&createCmdFlags.domain, "domain", "", "Team domain (e.g., pizzaknifefight). If not provided, derived from org name")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍕 praise: Toward common workplace shenanigan IIRC!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this line to just Team domain. If not provided, will be derived from org name, thinking we don't need to give an example of a domain. If it makes the messaging more fun / Slack-y I can bring it back!

Comment on lines +250 to +251
tests := []struct {
name string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
tests := []struct {
name string
tests := map[string]struct {

🧪 quibble: Let's use table tests here! I was confused in thinking "24h" was both the expected case and actual result at a glance...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👾 ramble: And perhaps a bounds of expected archive date might be most confident in testing? Like, some "24h" is greater than now but less than "48h" from now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, we have a standard table test format now and all of our other tests have been updated to use it. Let's use it here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated!

@zimeg zimeg added experiment Experimental feature accessed behind the --experiment flag or toggle enhancement M-T: A feature request for new functionality labels Mar 16, 2026
@zimeg zimeg added this to the Next Release milestone Mar 16, 2026
@zimeg zimeg changed the title feat: create and delete developer sandboxes feat(experiment): create and delete developer sandboxes Mar 16, 2026
Copy link
Member

@mwbrooks mwbrooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Looking good @vegeris! Thank you for adding the sandbox create and sandbox delete commands.

🧪 Local testing works well!

✏️ I've left some suggestions that I'd appreciate you handle before merging this PR. The 🔡 alphabetical ones feel like nits but go a long way for future maintainers who need to read and find content.

cmd.Flags().StringVar(&createCmdFlags.locale, "locale", "", "Locale (eg. en-us, languageCode-countryCode)")
cmd.Flags().StringVar(&createCmdFlags.template, "template", "", "Template ID for pre-defined data to preload")
cmd.Flags().StringVar(&createCmdFlags.eventCode, "event-code", "", "Event code for the sandbox")
cmd.Flags().StringVar(&createCmdFlags.archiveTTL, "archive-ttl", "", "Time-to-live duration; sandbox will be archived at end of day after this period (e.g., 2h, 1d, 7d)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: In the Long Description can be list all of the available formats for TTL? 1h, 1d, 1w?, 1m? 1y?, etc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point; I also updated the parsing of archiveTTL to only recognize day/week/month; no 'hour' option (though we'll likely look at adding support for these shorter archive times in the future)

},
}))
clients.IO.PrintInfo(ctx, false, "Manage this sandbox from the CLI or visit\n%s", style.Secondary("https://api.slack.com/developer-program/sandboxes"))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Excellent formatting choice!

eventCode string
archiveTTL string // TTL duration, e.g. 1d, 2h
archiveDate string // explicit date yyyy-mm-dd
partner bool
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to include support for the partner flag, since we have validation on the backend to make sure only partner developers can create partner sandboxes

}
if target.After(maxAllowed) {
return 0, slackerror.New(slackerror.ErrInvalidArchiveTTL)
}
Copy link
Contributor Author

@vegeris vegeris Mar 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏁 I added some basic validation around acceptable archive dates but I'm not sure if we want to keep this in the CI; the backend will error out if an invalid date is provided but the error message isn't particularly user friendly (it's the generic 'invalid_args' response). This at least highlights which arg is invalid

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I think I'll just include validation for 'date cannot be in the past' for the --archive-date flag and that's it. It's not possible to provide a date in the past for --archive-ttl anyway. This just leaves out any extra validation for max archive date (backend will return invalid_args)

@vegeris vegeris force-pushed the evegeris-sandbox-integration-create-delete branch from edcda2b to f6b4d21 Compare March 19, 2026 19:26
@vegeris vegeris force-pushed the evegeris-sandbox-integration-create-delete branch from cf4078f to 1b65aa8 Compare March 19, 2026 20:39
@vegeris
Copy link
Contributor Author

vegeris commented Mar 19, 2026

I'm going to go ahead and merge but happy to do a follow up if anything else comes up 🚀

@vegeris vegeris merged commit 55a4069 into main Mar 19, 2026
8 checks passed
@vegeris vegeris deleted the evegeris-sandbox-integration-create-delete branch March 19, 2026 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement M-T: A feature request for new functionality experiment Experimental feature accessed behind the --experiment flag or toggle semver:patch Use on pull requests to describe the release version increment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants