Release Content Gate
Release Content Gate
Section titled “Release Content Gate”A BoB release is a tag of this repository, and every client installs from it. Whatever is tracked at the release commit ships to every tenant. The release content gate refuses a release whose tree carries operator data, a client identifier or a credential (#2290, part of #2215).
Where it runs
Section titled “Where it runs”| Entry point | What it does |
|---|---|
bob release (stable, nightly, promote) |
Runs the gate after every other gate and before any bump, tag or push. A hit refuses with exit 3: one line with the hit count and the command that lists the hits. No tag is created. --dry-run runs the gate too. |
make check-release-content [REF=<sha>] |
The same check without releasing. It is not part of make check, because it needs an operator profile, and CI has none. |
node scripts/checks/release-content.js [--ref <sha>] [--root DIR] [--allow FILE] [--json] |
The engine. --ref defaults to HEAD. --allow grades against an uncommitted allow-list. |
BOB_RELEASE_CONTENT=<script> replaces the engine inside release.sh, the
same seam as BOB_RELEASE_DOCS.
The three rules
Section titled “The three rules”| Rule | What it refuses | Input |
|---|---|---|
path |
A tracked path that must not exist in a release tree | scripts/checks/release-content.json paths[], plus the session_state and machine_local paths of scripts/lib/derived-paths.json |
tenant |
A path or a line carrying a client identifier: repo names, org names, domains and product names | The operator profile’s tenants[] only (operator.json, schemas/operator.schema.json) |
credential |
A line matching a credential pattern that is not a placeholder | registry/skills/secrets-management/references/secret-patterns.json, the catalogue the commit secret scan reads too (#3662) |
Path patterns are anchored at the repo root. * matches within one path
segment, a leading **/ matches at any depth, and a trailing / matches the
directory and everything under it. except lists exact paths a pattern does
not cover. So apps/intake/config/ matches the operator’s intake config but
not apps/intake/config.example/. config/cloudflare-accounts.json does not
match the operator fixtures under tests/fixtures/operator/sample/. Operator
data (#2270), projects.json, and any secrets/ or memory/ directory are
covered. The rules file holds paths only, never a client name.
Tenant literals are matched case-insensitively as substrings of every
tracked path (a file named after the client ships its name; the hit has no
line) and of every tracked text line, including docs/, *.md, journal/,
requirements/ and CHANGELOG.md. Binary files’ contents are skipped. The product repo never names a
client in order to keep that client out: the names live only in the
operator’s profile.
"tenants": [ { "id": "client-a", "label": "Globex Corporation", "literals": ["globex", "globex-corp.example"] }]A tenant id is opaque. The allow-list in the product repo names tenants by
id, so an id that overlaps one of its own literals ("id": "globex") is a
config error.
Credential hits never reproduce the secret. A hit names the file, the
line and the pattern. The match is masked to its first four characters
(ghp_****), and the line itself is never kept. A line matching the
catalogue’s placeholder regex (REPLACE_ME, EXAMPLE, ${VAR}, …) is an
example, not a hit.
Output and exit codes
Section titled “Output and exit codes”release-content — /home/me/projects/bigbrain at HEAD (44203325) operator: example-co (via default) tenants: client-a graded: 2145 tracked file(s) · 39 path rule(s) · 10 credential pattern(s) allow-listed: path 1 · tenant 289 · credential 24 (scripts/checks/release-content-allow.json) PASS no operator data, client identifiers or credentials in the release tree--json emits release-content/1: root, ref, sha, verdict
(clean / hits), operator, tenants (ids), rules, hits[] (one per
file, line, rule and tenant id; pattern and the masked match for a
credential), allowed (count per rule) and unused_allow[]. On exit 2 or 3
the document carries verdict config-error / no-operator and error.
| Exit | Meaning |
|---|---|
| 0 | Clean: every hit, if any, is allow-listed |
| 1 | Hits: a release of this tree would ship them |
| 2 | Invalid config: the rules, the catalogue, the profile’s tenants[] or the allow-list |
| 3 | No operator resolved: the gate cannot know which clients to keep out, so it fails closed |
The allow-list
Section titled “The allow-list”scripts/checks/release-content-allow.json is read from the graded tree at
<ref>, so a release carries its own baseline. Entries are
{path, rule, tenant, why, retires}:
pathis a file or a directory prefix (trailing/).ruleispath,tenantorcredential.tenantis required for ruletenant. It is an id the operator profile declares, never a literal. An undeclared id is a config error.whyandretiresare required.retiresnames the requirement that removes the entry.- The allow-list is graded like any other file, so it must not name a client either. A file whose name carries the client is allow-listed by its directory, not by its own path.
The allow-list is loaded by abs-path-lint.js’s loader, not by a second
parser. Every run prints the allow-listed count per rule and lists the
entries that match nothing, so the burn-down stays visible.
The baseline at #2290 allow-lists four groups, each against a follow-on requirement:
| Group | Retired by |
|---|---|
The eloqua-dev skill’s as-built client material |
#3430 — retired: the client notes live in the operator repo’s skills/eloqua-dev/ |
| Tenant literals in docs, briefings, tests, scripts, journal and CHANGELOG | #3431 |
projects.json, the derived registry (path and tenant) |
#3432 — retired: the registry is operator data in the operator repo |
| Credential-shaped samples in tests and doc examples | #3433 |
Related
Section titled “Related”- Credential Inventory covers credentials by name. This gate covers the tree.
- Versioning explains the release channels and the other gates.
- Operator describes the profile that declares
tenants[]. check-abs-paths(#2268) keeps the operator’s own identity literals out of synced files during development. This gate grades the whole tree at the release commit, docs included, for every declared tenant.