Skip to content

ci: keep production secrets in the production environment - #95

Merged
kalaspuff merged 1 commit into
mainfrom
fctl/47-tell-me-what-s-needed-to-be-done-in-the
Oct 18, 2026
Merged

kalaspuff merged 1 commit into
mainfrom
fctl/47-tell-me-what-s-needed-to-be-done-in-the

Conversation

@fctl-sh

@fctl-sh fctl-sh Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Release's publish job (which uses CLOUDFLARE_API_TOKEN) and CI's site-docs job (which uses SITE_DEPLOY_KEY) now run in the production environment, as the deploy job already does.

Why

Before the repositories go public:

  • Today, any branch can read the production secrets. production has no branch rule, and the secrets are repository secrets. The run logs show Release's publish job receives CLOUDFLARE_API_TOKEN without an environment. Agent sessions' tokens have contents: write and workflows: write, so a workflow on any branch an agent pushes can read the Cloudflare token (which can redeploy app.fctl.sh) and SITE_DEPLOY_KEY (which can push to fctl-site's main, and so change fctl.sh/install).
  • This PR is the first half of the fix. Once it's merged, an admin moves those secrets into the production environment and limits the environment to main. Workflows on other branches then can't read them.
  • Order matters. Jobs in an environment can still read repository secrets, so merging this first breaks nothing. Move the secrets afterwards.

docs/development.md says where these secrets live.

How I verified it

  • actionlint 1.7.12 passes on .github/workflows/.
  • The deploy job has run in production all along, so the environment: key works with these workflows' permissions.
  • publish runs from main (a workflow_dispatch on main), so a main-only policy allows it, including tag rebuilds.
  • Merging this runs site-docs (docs/ changed), which checks the job inside the environment.

Refs #22. Session: https://app.fctl.sh/s/ses_01M58A7MAFDWKZDCA239GR6H6G

Related pull requests

Merge before the flip:

Merge after the flip (drafts until then):

Release's publish job (the Cloudflare token) and CI's site-docs job
(SITE_DEPLOY_KEY, which can push to fctl-site's main and so change
fctl.sh/install) now run in the production environment, like the deploy
job already does. Once those secrets move from the repository into the
environment and the environment only allows main, a workflow on any
other branch cannot read them. Agent sessions can push branches with
workflow changes, and once the repositories are public anyone can write
the issues and comments agents read.

Refs #22
@kalaspuff
kalaspuff merged commit 36c07f7 into main Oct 18, 2026
7 checks passed
@kalaspuff
kalaspuff deleted the fctl/47-tell-me-what-s-needed-to-be-done-in-the branch October 18, 2026 20:55
kalaspuff pushed a commit to hyperstructure/fctl-site that referenced this pull request Oct 18, 2026
Adds a `SECURITY.md`, as hyperstructure/fctl and hyperstructure/sandbox
have. Reports go through GitHub's private vulnerability reporting, which
an admin turns on once the repository is public.

fctl.sh serves `/install`, which people pipe to `sh`, so reports about
the site shouldn't land in public issues.

This can merge before or after the repositories go public. Part of
making fctl, fctl-site and design public: hyperstructure/fctl#95,
hyperstructure/fctl#96, #17,
hyperstructure/design#12, hyperstructure/sandbox#4.

Session: https://app.fctl.sh/s/ses_01M58A7MAFDWKZDCA239GR6H6G

Co-authored-by: fctl-sh[bot] <fctl-sh[bot]@users.noreply.github.com>
@fctl-sh
fctl-sh Bot restored the fctl/47-tell-me-what-s-needed-to-be-done-in-the branch October 18, 2026 21:10
kalaspuff pushed a commit to hyperstructure/fctl-site that referenced this pull request Oct 18, 2026
**Merge only after hyperstructure/fctl and hyperstructure/design are
both public.** Until then the build can't reach them without the deploy
keys, so CI on this pull request fails. Re-run it after the flip.

## What changes

- The `build` job no longer sets up `DESIGN_DEPLOY_KEY` and
`FCTL_DEPLOY_KEY`, or the git URL rewrites that sent GitHub fetches over
SSH.
- `AGENTS.md` says where CI's secrets live now (the `production`
environment) and that building needs no keys.

## Why it works without the keys

- **The design package.** npm downloads it as a tarball over HTTPS from
codeload.github.com. The lockfile's `git+ssh://` URL doesn't force SSH.
I checked this with npm 10.9 and SSH disabled, using a public GitHub
dependency.
- **fctl's docs.** `scripts/docs.mjs` fetches the commit in
`fctl-docs.ref` by SHA over HTTPS. GitHub serves that to anyone for a
public repository. I checked this anonymously against the public
hyperstructure/sandbox.
- **Order matters.** Merge this before deleting the keys. With an empty
key, the old step still rewrites
`https://github.com/hyperstructure/fctl.git` to SSH, so the docs build
would fail.

## After merging

An admin deletes both secrets here, and the read deploy keys on
hyperstructure/design and hyperstructure/fctl.

## Related

- hyperstructure/fctl#95: production secrets move into the environment
(before the flip)
- hyperstructure/fctl#96: fctl's own deploy-key cleanup (after the flip)
- hyperstructure/design#12 and hyperstructure/sandbox#4: wording (after
the flip)

## Verified

actionlint 1.7.12 passes.

Session: https://app.fctl.sh/s/ses_01M58A7MAFDWKZDCA239GR6H6G

Co-authored-by: fctl-sh[bot] <fctl-sh[bot]@users.noreply.github.com>
kalaspuff pushed a commit to hyperstructure/design that referenced this pull request Oct 18, 2026
**Merge after this repository is public.**

- **README.** The README said to depend on a tag *because* the
repository was private. Once it's public, npm downloads the tagged
package from GitHub without signing in, so the README says that instead.
- **SECURITY.md.** A security policy, as hyperstructure/fctl and
hyperstructure/sandbox have. Reports go through GitHub's private
vulnerability reporting, which an admin turns on once the repository is
public.

Part of making fctl, fctl-site and design public:
hyperstructure/fctl#95, hyperstructure/fctl#96 and
hyperstructure/fctl-site#17 drop the deploy keys that read this
repository.

Session: https://app.fctl.sh/s/ses_01M58A7MAFDWKZDCA239GR6H6G

---------

Co-authored-by: fctl-sh[bot] <fctl-sh[bot]@users.noreply.github.com>
kalaspuff pushed a commit to hyperstructure/sandbox that referenced this pull request Oct 18, 2026
**Merge after hyperstructure/fctl is public.** `AGENTS.md` told agents
to link to https://fctl.sh instead of fctl's files because
hyperstructure/fctl was private. Once it's public, they can link to its
code as well.

Part of making fctl, fctl-site and design public:
hyperstructure/fctl#95, hyperstructure/fctl#96,
hyperstructure/fctl-site#17 and hyperstructure/design#12.

Session: https://app.fctl.sh/s/ses_01M58A7MAFDWKZDCA239GR6H6G

Co-authored-by: fctl-sh[bot] <fctl-sh[bot]@users.noreply.github.com>
kalaspuff pushed a commit that referenced this pull request Oct 18, 2026
)

**Merge only after hyperstructure/design is public.** Until then `npm
ci` can't reach the design package without the key, so CI on this pull
request fails. Re-run it after the flip.

## What changes

- CI's `check`, `dev` and `deploy` jobs and Release's `publish` job stop
setting up `DESIGN_DEPLOY_KEY`.
- The `repo-access` action is now used only by `site-docs`, which pushes
fctl.sh's docs pin to fctl-site with `SITE_DEPLOY_KEY`. Its description
no longer talks about private repositories.
- `AGENTS.md`, `docs/development.md` and `ROADMAP.md` no longer say the
repositories are private. Moving `@hyperstructure/design` to npm stays
on the roadmap as its own item, but it isn't needed to drop the keys.

## Why no lockfile change

The lockfile records
`git+ssh://git@github.com/hyperstructure/design.git#<sha>`. For a GitHub
dependency, npm first downloads the commit's tarball over HTTPS
(codeload.github.com) and falls back to git only when that fails. For a
public repository, that download needs no sign-in.

I checked this with npm 10.9 and a public GitHub dependency
(`github:sindresorhus/is-plain-obj#v4.1.0`), with SSH disabled
(`GIT_SSH_COMMAND=/bin/false`) and no git config:
- `npm install` wrote a `git+ssh://` URL into the lockfile.
- `npm ci` from that lockfile succeeded.

`cargo xtask dev` installs with `npm ci` too.

## After merging

An admin deletes the `DESIGN_DEPLOY_KEY` secret here and the deploy key
on hyperstructure/design. fctl-site's matching change is linked below.

## Verified

- actionlint 1.7.12 passes.
- Before the flip, CI is expected to fail at `npm ci`.

Refs #22. Session: https://app.fctl.sh/s/ses_01M58A7MAFDWKZDCA239GR6H6G

## Related pull requests

Merge before the flip:
- #95: production secrets move into the production
environment
- hyperstructure/fctl-site#18: a security policy (any time)

Merge after the flip (drafts until then):
- #96: fctl stops using DESIGN_DEPLOY_KEY
- hyperstructure/fctl-site#17: fctl-site stops using DESIGN_DEPLOY_KEY
and FCTL_DEPLOY_KEY
- hyperstructure/design#12: README no longer says the repository is
private
- hyperstructure/sandbox#4: AGENTS.md no longer says fctl is private

Co-authored-by: fctl-sh[bot] <fctl-sh[bot]@users.noreply.github.com>
@kalaspuff
kalaspuff deleted the fctl/47-tell-me-what-s-needed-to-be-done-in-the branch October 18, 2026 22:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant