Skip to content

Public release AMIs, entity-wide licenses and trial keys - #6

Merged
hkd987 merged 2 commits into
mainfrom
claude/trusting-noether-fc3z2n
Sep 28, 2026
Merged

hkd987 merged 2 commits into
mainfrom
claude/trusting-noether-fc3z2n

Conversation

@hkd987

@hkd987 hkd987 commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Two changes that follow from licensing Sandy the way RunsOn is licensed, for the Weft license service (weftsh/license):

1. Publish release AMIs publicly (564aae9)

A release's host AMIs become public in every release Region, like the rest of a release (template, container images, guest artifacts), and a license becomes a term of use rather than an image permission. This replaces the plan to grant launch permission account by account, which would have needed EC2 permissions on the license server and left a customer unable to launch hosts until a grant landed.

  • deploy/packer/weft-host.pkr.hcl: ami_groups = ["all"], applied to every Region copy.
  • .github/workflows/release.yml: before building, checks that block public access for AMIs is off in every release Region (it is on by default in newer accounts, and would otherwise fail the build an hour in). After building, asks EC2 whether each Region's AMI is public and fails the release if any is not.
  • deploy/README.md: the release role needs ec2:ModifyImageAttribute and ec2:GetImageBlockPublicAccessState, and block public access for AMIs must be off.
  • docs/licensing.md: a license covers every AWS account of the entity it is issued to (keys carry an empty accounts list); trial keys are marked trial.

2. Say a trial key is a trial in license status (47b892a)

A trial key was reported in a paid license's words: "The license expires in 15 day(s)" from its first day, then "… unless it is renewed" after an unpaid trial ended, though a trial is not renewed. evaluateLicense now reports trial. It says when a trial ends, and that the full key is emailed when the first payment clears and has to be installed over the trial key. State and release access are unchanged: a trial reads expiring and keeps the usual 30-day release grace. The SDK's LicenseStatus gains an optional trial.

Review. This touches deploy/, .github/workflows/ and packages/license/, so it needs two code-owner approvals.

Testing

  • Packer 1.16.1 fmt -check and validate -syntax-only; actionlint 1.7.7 on the release workflow. The release workflow itself has not run: the new public-AMI steps are proved only by a release.
  • pnpm -r run build, pnpm -r run typecheck, pnpm test (license 22, control plane 51 + 1 skipped for DynamoDB Local, SDK 7). The two new status tests fail against the previous status.ts.
  • The license service's contract suite already runs Sandy's own verifier, control plane and weft-sandbox CLI against trial keys and entity-wide keys at 740a8d6. It will be re-pinned to this change once it merges.

🤖 Generated with Claude Code

https://claude.ai/code/session_015mvSf18rAT2jxFY9d7GNFF


Generated by Claude Code

Modelled on RunsOn: a release's host AMIs are public in every release
Region, like the rest of a release (template, container images, guest
artifacts), and a license is a term of use rather than an image
permission. This replaces the plan for the license service to grant
launch permission account by account, which needed EC2 permissions on
the license server and left a customer unable to launch hosts until a
grant landed.

- Packer: ami_groups = ["all"], applied to every Region copy.
- Release workflow: before building, check that block public access for
  AMIs is off in every release Region (it is on by default in newer
  accounts and would fail the build an hour in); after building, ask EC2
  that every Region's AMI is public, and fail the release if not.
- Docs: the license covers every AWS account of the entity it is issued
  to (keys carry an empty `accounts` list); trial keys are marked `trial`;
  the release role needs ModifyImageAttribute and
  GetImageBlockPublicAccessState.

Checked with packer 1.16.1 (fmt -check, validate -syntax-only) and
actionlint 1.7.7 on the release workflow; the license package's
typecheck and tests pass. The release workflow itself has not run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mvSf18rAT2jxFY9d7GNFF
A trial key (payload `trial: true`, issued for 15 days) was reported in
a paid license's words. From its first day it read "The license expires
in 15 day(s)", and once the trial ended unpaid, "The license expired N
day(s) ago ... unless it is renewed" — but a trial is not renewed. It
becomes a full key when the first payment clears, and that key has to
be installed over the trial's. The license service's daily check
already said "This is a trial key", so an admin saw the two sentences
side by side, disagreeing.

evaluateLicense now reports `trial` and says what a trial is:

- while it runs: "The trial ends in N day(s). The full license key is
  emailed when the first payment clears; install it to replace this one."
- after it ends: "The trial ended N day(s) ago ... If you have
  subscribed, install the full license key Weft emailed you", and once
  the release grace is over, "The trial has ended ... Install a full
  license key to receive them."

State and release access are unchanged: a trial still reads `expiring`
(it ends within 30 days) and keeps the same 30-day release grace as any
lapsed key. The SDK's LicenseStatus gains an optional `trial`, and
docs/licensing.md describes it.

Pinned by two tests that fail against the previous status.ts: a trial
walked through running, ended and past the grace, never using a paid
license's words; and a full key never called a trial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015mvSf18rAT2jxFY9d7GNFF
@hkd987
hkd987 merged commit a1b6206 into main Sep 28, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants