Skip to content

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

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

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

Conversation

@vegeris

@vegerisvegeris commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

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

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

codecovBot commented Mar 11, 2026

Copy link
Copy Markdown

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 linesPatch %Lines
cmd/sandbox/create.go84.66%20 Missing and 5 partials ⚠️
cmd/sandbox/delete.go73.52%14 Missing and 4 partials ⚠️
internal/api/sandbox.go95.83%1 Missing and 1 partial ⚠️
internal/style/style.go0.00%2 Missing ⚠️
cmd/sandbox/sandbox.go66.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
vegerisforce-pushed the evegeris-sandbox-integration-create-delete branch 2 times, most recently from 98ecc15 to f200970CompareMarch 11, 2026 23:43
@vegeris
vegerisforce-pushed the evegeris-sandbox-integration-create-delete branch from f200970 to cea2bcdCompareMarch 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 ownerMarch 12, 2026 19:00
Comment threadcmd/sandbox/create.go
},
}))
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
Copy Markdown
ContributorAuthor

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
Copy Markdown
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!

Comment threadcmd/sandbox/delete.go
}

return nil
}

Copy link
Copy Markdown
ContributorAuthor

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
Copy Markdown
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
Copy Markdown
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
vegerisforce-pushed the evegeris-sandbox-integration-create-delete branch from b23fbe4 to a35fbc3CompareMarch 12, 2026 19:09
Comment threadcmd/sandbox/create.go

@zimegzimeg left a comment

Copy link
Copy Markdown
Member

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 🚢 💨

Comment threadinternal/api/sandbox.go
Comment threadcmd/sandbox/sandbox.go
// 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
Copy Markdown
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!

Comment threadcmd/sandbox/create.go Outdated
Comment threadcmd/sandbox/create.go Outdated
Comment threadcmd/sandbox/delete.go Outdated
Comment threadcmd/sandbox/delete.go
}

return nil
}

Copy link
Copy Markdown
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 threadcmd/sandbox/create.go Outdated
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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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 👀

Comment threadcmd/sandbox/create.go Outdated
}

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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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 threadcmd/sandbox/create_test.go Outdated
Comment on lines +250 to +251
tests := []struct {
name string

Copy link
Copy Markdown
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 {
namestring
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Updated!

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

@mwbrooksmwbrooks left a comment

Copy link
Copy Markdown
Member

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.

Comment threadcmd/sandbox/create.go
Comment threadcmd/sandbox/create.go Outdated
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
Copy Markdown
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
Copy Markdown
ContributorAuthor

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)

Comment threadcmd/sandbox/create.go Outdated
Comment threadcmd/sandbox/create.go Outdated
Comment threadcmd/sandbox/create.go
},
}))
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
Copy Markdown
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!

Comment threadinternal/api/api_mock.go Outdated
Comment threadinternal/api/sandbox.go Outdated
Comment threadinternal/api/sandbox.go Outdated
Comment threadinternal/api/sandbox.go
Comment threadinternal/api/sandbox.go Outdated
Comment threadcmd/sandbox/create.go
eventCode string
archiveTTL string // TTL duration, e.g. 1d, 2h
archiveDate string // explicit date yyyy-mm-dd
partner bool

Copy link
Copy Markdown
ContributorAuthor

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

Comment threadcmd/sandbox/create.go Outdated
Comment threadcmd/sandbox/create.go
}
if target.After(maxAllowed) {
return 0, slackerror.New(slackerror.ErrInvalidArchiveTTL)
}

@vegerisvegerisMar 19, 2026

Copy link
Copy Markdown
ContributorAuthor

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
Copy Markdown
ContributorAuthor

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
vegerisforce-pushed the evegeris-sandbox-integration-create-delete branch from edcda2b to f6b4d21CompareMarch 19, 2026 19:26
@vegeris
vegerisforce-pushed the evegeris-sandbox-integration-create-delete branch from cf4078f to 1b65aa8CompareMarch 19, 2026 20:39
@vegeris

Copy link
Copy Markdown
ContributorAuthor

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 mainMar 19, 2026
8 checks passed
@vegeris
vegeris deleted the evegeris-sandbox-integration-create-delete branch March 19, 2026 22:02
@zimegzimeg mentioned this pull request Apr 20, 2026
2 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancementM-T: A feature request for new functionalityexperimentExperimental feature accessed behind the --experiment flag or togglesemver:patchUse on pull requests to describe the release version increment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@vegeris@mwbrooks@zimeg