Repo bootstrap
This page helps you set up a GitHub repo the way your organization wants it in one step. By the end, the repo
has a ruleset on its default branch, a CODEOWNERS file and a README, the Actions variables and secrets its
workflows need, and the Dependabot secrets its Dependabot updates need.
New repos start bare. A bootstrap policy describes what every repo should get, and By Dawn applies it when
you bootstrap a repo: a project admin does it from the project’s Repos page, and a worker can run saw repo bootstrap <repo>. Bootstrap never overwrites a file, and running it twice changes
nothing, so it’s safe to run on a repo you’ve already set up.
What a policy holds
Section titled “What a policy holds”An org admin sets the organization’s policy in Settings, then Organization, then GitHub, on the Repo bootstrap card. A project admin can give one project its own in Settings, then This project, then GitHub: the card says Inherited from the org until you choose Set a policy for this project, and Use the org policy goes back. A project policy replaces the organization’s as a whole, so a project that sets one uses only its own. Everyone else sees the policy but can’t change it.
A policy is off until you turn on Bootstrap repos (“Lets project admins and agents bootstrap repos.”). Then it has four parts:
| Part | What By Dawn does with it |
|---|---|
| Default-branch ruleset | With Add the ruleset on, creates a ruleset named SAW default branch on the repo’s default branch. It can Require a pull request with 0 to 6 Required approvals, Dismiss stale approvals when new commits are pushed, Block force pushes, Block deleting the branch, and require Required status checks by name. |
| Files | Adds CODEOWNERS and README.md from your templates, but only where the repo doesn’t have them yet. Leave a template empty to skip that file. |
| Actions variables | Creates or updates repo-level Actions variables. They’re plain text, readable by anyone with access to the repo. To set one variable outside a policy, an agent runs saw variable set (see Actions variables). |
| Secrets to push | Copies By Dawn secrets into the repo’s Actions secrets, its Dependabot secrets, or both, optionally under a different name on GitHub. A secret the repo already has is kept. |
Templates can use {{repo}} (the repo’s name), {{project}} (the project’s name) and {{org}} (your GitHub
organization’s login). For example, * @{{org}}/maintainers becomes * @acme/maintainers.
Actions or Dependabot
Section titled “Actions or Dependabot”GitHub keeps a repo’s secrets in separate stores, and each one is read by a different thing:
- Actions secrets are what your workflows read as
secrets.NAME. - Dependabot secrets are what Dependabot reads when it updates dependencies. That includes the credentials
for a private package registry in the
registries:block of.github/dependabot.yml.
Neither can see the other. If .github/dependabot.yml reads ${{secrets.PACKAGES_TOKEN}} and the repo has only an
Actions secret of that name, Dependabot can’t authenticate to your registry and every update run fails. So each
secret in a policy names where it goes: tick Actions, Dependabot, or both on its row. A secret going to both
is pushed twice under the same name, once to each store. Over the API this is the secret’s stores, and a
secret without it goes to Actions only.
Only organization and project secrets can be pushed to a repo, because a personal secret belongs to one
person and shouldn’t end up in everyone’s CI. The secret picker only offers those, and By Dawn refuses to save a
policy that names any other (repo_bootstrap_secret_scope_invalid).
Bootstrap a repo
Section titled “Bootstrap a repo”On the project’s Repos page, a project admin chooses Bootstrap repo… in the repo’s ⋯ menu. It’s offered for GitHub repos. The dialog sums up what the policy will set up, for example “Sets up default-branch ruleset, CODEOWNERS, 1 variable and 1 secret.”, and whether the policy is the project’s or the organization’s. Choose Bootstrap now, or Bootstrap again on a repo that has been bootstrapped before. If the project’s policy is off, the dialog says so and Open settings takes you to it.
The repo’s row then shows a badge for its latest run:
| Badge | Meaning |
|---|---|
| Bootstrapped | Every item applied, already matched or was already there. |
| Secrets pending | At least one secret waits for a By Dawn agent to push it (why). This badge wins while it lasts, so check the dialog for any other item that didn’t apply. |
| Partly bootstrapped | At least one item didn’t apply: a permission is missing, GitHub’s plan has no rulesets, or GitHub refused. The dialog says which. |
| Bootstrap refused | Nothing could run, for example because By Dawn’s GitHub App can’t reach the repo. The dialog says why. |
The dialog lists every item of the latest run, says whether a person or a By Dawn agent ran it, and gives each item one of the results in What a run does.
Over the API
Section titled “Over the API”Over the API, the organization’s policy is one object:
PUT https://workspace.dev.sawrun.com/api/v1/orgs/{orgId}/organization/repo-bootstrap-policyAuthorization: Bearer eyJ…Content-Type: application/json
{ "enabled": true, "ruleset": { "enabled": true, "requirePullRequest": true, "requiredApprovals": 1, "dismissStaleReviews": false, "blockForcePush": true, "blockDeletion": true, "requiredStatusChecks": ["build"] }, "files": { "codeowners": "* @{{org}}/maintainers\n", "readme": "# {{repo}}\n\nPart of {{project}}.\n" }, "variables": [ { "name": "DEPLOY_ENV", "value": "dev" } ], "secrets": [ { "name": "NPM_TOKEN", "scope": "org", "githubName": null, "stores": ["actions", "dependabot"] } ]}A project’s policy lives at …/projects/{projectId}/repo-bootstrap-policy. Reading it returns the project’s
own policy (override, or null), the one that applies (effective), and where that comes from
(source: org or project). DELETE goes back to the organization’s.
Variable and secret names follow GitHub’s rules: letters, digits and _, not starting with a digit or with
GITHUB_. A policy holds up to 50 of each. stores is actions, dependabot or both, with no repeats, and two
secrets can’t push the same name to the same store.
What a run does
Section titled “What a run does”By Dawn works through the policy in this order: files, variables, secrets, then the ruleset. The ruleset goes last because a rule requiring pull requests would otherwise block By Dawn’s own first commit.
Each item reports what happened. The dialog shows the label, and the API the value next to it:
| Result | API value | Meaning |
|---|---|---|
| Applied | applied |
By Dawn wrote it. |
| Unchanged | unchanged |
It already matched the policy. |
| Already there | skipped_exists |
The file (or secret) is already there, so By Dawn left it alone. |
| Not on this GitHub plan | unavailable_plan |
The ruleset couldn’t be created: GitHub doesn’t offer rulesets on private repos in the Free plan. Everything else still applies. |
| Permission missing | permission_missing |
By Dawn’s GitHub App hasn’t been given the permission this item needs (see Permissions on GitHub). |
| Waiting for an agent | pending |
A secret waiting for a By Dawn agent to push it (see below). |
| Failed | failed |
GitHub refused for another reason. The item says what it answered (detail). |
To bootstrap a repo over the API, POST to …/projects/{projectId}/repos/{repoId}/bootstrap. The answer is the
run: its items (a secret’s item also says which store it went to), an overall status (completed, partial, pending_secrets or refused) and, when
something stopped it, a refusal with a slug and an acceptUrl. GET …/projects/{projectId}/repo-bootstrap-runs returns the latest run for each repo in the project. A slug
is a fixed error code you can branch on, and Responses and errors explains
them.
Why secrets are pushed by an agent
Section titled “Why secrets are pushed by an agent”By Dawn secrets are end-to-end encrypted, so By Dawn’s servers can’t read them, and that includes pushing them to GitHub. A repo’s secrets have to be sealed with the repo’s own public key before GitHub accepts them, and its Actions and Dependabot secrets each have their own key. So a By Dawn agent that’s allowed to read the secret seals it on its own machine, and only the sealed value passes through By Dawn to GitHub. Nobody but GitHub can open it.
That’s why secrets come back Waiting for an agent when you choose Bootstrap now, and the dialog says “Secrets will be pushed by the next SAW agent that bootstraps this repo.” A worker pushes them the next time it runs:
saw repo bootstrap <repo> [--overwrite-secrets]Agents can also call the same thing as the saw_repo_bootstrap tool. It prints one line per item:
file CODEOWNERS: skipped_existsfile README.md: appliedvariable DEPLOY_ENV: unchangedsecret NPM_TOKEN: appliedsecret NPM_TOKEN (dependabot): appliedruleset SAW default branch: appliedA secret’s line without a store is its Actions copy, and (dependabot) marks its Dependabot copy.
By default a secret the repo already has is left alone (skipped_exists). Pass --overwrite-secrets to
replace it, which is how you rotate a secret into the repo. The command only works on a repo bound to the
ticket, and not from a read-only run such as planning.
An agent that needs one more Actions variable, rather than the policy’s, runs saw variable set instead. See
Actions variables.
Permissions on GitHub
Section titled “Permissions on GitHub”Bootstrap needs four repository permissions on By Dawn’s GitHub App beyond the usual ones: Administration
(for the ruleset), Secrets, Dependabot secrets and Variables, all read and write. If your organization installed the App
before it asked for them, GitHub holds the request until an owner accepts it. Until then, those items report
Permission missing, and the dialog shows Accept the App’s permissions on GitHub (over the API, the run’s
refusal is github_bootstrap_permission_missing with an acceptUrl). Open it as an owner of the GitHub
organization, review the request and accept it. By Dawn keeps these
permissions inside its own GitHub service and uses each one for a single repo at a time.
Do and don’t
Section titled “Do and don’t”- Do turn the ruleset on last when you adopt bootstrap on existing repos. Try a policy with only files and variables first, check the results, then add the ruleset.
- Do list the status checks your CI actually reports. A required check that never runs blocks every pull request.
- Don’t expect bootstrap to update a
CODEOWNERSor README you changed in the template. It only adds missing files, so change existing ones by pull request.
Next, see Branching and CI to make By Dawn’s branches match your CI.