On this page
Implementation status
The final record of what CommonLayer implements, where, how it was tested and where that
testing happened, and what is not done. It is compiled from the work-package status
files in docs/status/ (WP-01 to WP-81), the
security review of November 2026, and the
list of GitHub Actions runs of this repository as read on 2026-11-10 around 22:40 UTC.
Where a status file and the code disagreed, the code was read and this page follows it.
Repository stewardship and onboarding through the GitHub App (WP-80, WP-81;
plan 13) were added on 2026-11-11. Their commits
were pushed without workflow runs to save runner minutes
(ADR-0048); the final tree (0c3ffd0) was then checked
on GitHub runners by ci, security, docs and infra. What ran for the stewardship
work, and where, is stated in each section below.
After that, the first-party projects were corrected (WP-83,
plan 14,
ADR-0049): the base image,
nginx, Valkey and PostgreSQL had been built as directories of this repository, by its
workflows. Each is now a complete repository tree of its own
(commonlayer-org/<project>), kept under projects/ only until those repositories
exist. The same day a missing object storage bucket became its own error, the
development GitHub learned to serve a project directory of the checkout, and a helper
registers the GitHub App from a manifest (WP-82).
On 2026-11-12 the portal was reworked by one rule, "don't make me think" (WP-90, plan 15): every page says where you are, what the state is and what to do next; dashboards start with what is waiting; explanations moved behind disclosures or into the documentation. A check holds 117 page types to the countable parts of that rule.
Words used on this page:
- Tested locally: automated tests or a scripted drill ran and passed in the build sandbox (linux/amd64, Docker 29, one shared machine), as recorded in a status file.
- Tested on a GitHub runner: a workflow job ran and passed on a GitHub-hosted runner
(
ubuntu-24.04, linux/amd64). The run id is given. - Validated statically: linted, schema-checked, rendered or unit-tested as configuration, but never executed against the thing it configures.
- Never run: exists in the repository; nothing has executed it.
Nothing is in production. No artifact has been published to a CommonLayer registry, no contribution has been accepted with real money, and no payout has been made.
Not done or not verified
Read this section before relying on any part of the platform. It is ordered by consequence: what has never run at all, then what ran only on GitHub runners or only locally, what is implemented only in part, and the decisions that only the operating entity can make.
Never run anywhere
| Item | What exists instead |
|---|---|
The four first-party projects as repositories on GitHub (commonlayer-org/base, commonlayer-org/nginx, commonlayer-org/valkey, commonlayer-org/postgresql): they do not exist yet. Their own workflows (validation per version line, the checkout of the base project through CL_BASE_REPOSITORY, release, scheduled scan) have never run | Each tree was exported to a directory outside this checkout and built there (see "Ran only locally"); the workflows were checked with actionlint in the exported trees. Creating the repositories and pushing the exports (scripts/export-project.sh) is the owner's step |
scripts/ops/github-app-create.py against github.com | Tested against a local stand-in for GitHub: manifest, state check, exchange, files readable by the owner only, no secret printed |
| The GitHub App and everything behind it on github.com: the installation callback and its code exchange, installation tokens, the repository picker, collaborator invitations and removals, mirror clones with an installation token, transfer webhooks, a stewardship-hosted restore | No GitHub App has been created for this platform. The code paths are tested against an in-memory GitHub, wiremock and local bare repositories, and one test mirrors a small public repository over HTTPS without a token. In development a labelled stand-in replaces GitHub (github.provider = "development", refused elsewhere). The operator guide (the GitHub App) lists the settings the code expects and says they are unverified |
| Keyless signing and its verification (Fulcio, Rekor, Sigstore TUF root, GitHub Actions OIDC identities) | The pipeline's keyless code path and the template's release workflow exist. The publish drill signed with a cosign key pair without a transparency-log entry (COMMONLAYER__REGISTRY__COSIGN_REQUIRE_TRANSPARENCY_LOG=false, refused in production) |
Provenance from actions/attest-build-provenance discovered and verified by the pipeline (threat model O11) | The drill's provenance is an SLSA v1 statement written and signed by scripts/dev/e2e-publish.sh itself; it proves parsing and checking, not that a build service attested anything |
Any release workflow: release (platform images), every project's own release.yml and scheduled security-scan.yml (in the four trees and the template), ops | actionlint and shellcheck clean; a WP-20 rehearsal against a throwaway local registry covered push by digest, index merge, release SBOMs and chart publication. No GitHub run of these workflows is recorded. This repository no longer has workflows that release or rescan projects |
| linux/arm64 builds of any image | The workflows build arm64 only when the repository is public or the variable CL_ARM64_RUNNER names a runner; neither is the case. Release workflows refuse to release without arm64 |
| Live Stripe: payments, refunds, disputes, fees, invoice-payment linking, subscriptions | Tested against fixtures built from the API reference and a mock server (crates/commonlayer-funding/tests/it/stripe.rs). Which invoice_payments list filters Stripe accepts was taken from the object reference, not observed |
| Live payouts through Stripe Connect | Only against a mock; simulated payout runs are tested |
| A real GitHub App installation (webhooks from GitHub, App API calls, the GitHub issue channel) and a real Actions OIDC token at a deployed platform | GitHub's documented example payloads, wiremock and locally generated keys; the acceptance tests use the test kit's OIDC verifier |
| Repository verification and manifest sync against GitHub | The SSRF-safe client deliberately ignores the sandbox's egress proxy. The drill used clctl dev manifest-sync (development only) and the seed's pre-verified repository |
| The numeric-id check of a repository against GitHub (review MEDIUM-5 fix) | Tested with wiremock (repositories::numeric_github_ids_are_checked_and_cannot_be_squatted) |
| Security feeds against the real services (OSV, EPSS, CISA KEV, NVD) | Recorded responses only; the FeedStale alert is pending in every local stack because the feeds cannot be fetched |
| CloudNativePG backups (Barman Cloud Plugin, volume snapshots), the Pooler, PodMonitor, synchronous replication | Chart values and CRD schema validation only |
| Anything on a real Kubernetes cluster or on AWS | kind in CI (see below); OpenTofu modules validated (tofu validate, tflint) but never planned or applied |
| The Playwright suite on a GitHub runner, and against the containerised stack | The suite ran green locally against the development backend (below). The e2e workflow's only run (Dependabot pull request, commit f920636) failed before any test; it has been changed since and has not run again |
Load and stress profiles of the k6 scenarios; the webhook-ingestion scenario | Smoke runs of three scenarios against the Compose stack (WP-50) |
| Email to real mailboxes | Mailpit only |
| Platform images signed or attested (threat model O12) | The release workflow would sign and attest them; it has never run |
| A data-subject request process (export, deletion of personal data while keeping financial and audit records) | Not implemented |
Ran only on GitHub runners
| Item | Evidence | Caveat |
|---|---|---|
CloudNativePG high availability: operator install, three instances, failover (primary killed, standby promoted in about 3 s, data kept, old primary rejoined), rolling update, helm test | projects run 42882522865 (commit a562cb9), job projects/postgresql 18 (amd64) | Passed in its original form (run 42882522865) and again after the test moved into chart hooks (projects/postgresql/tests/kind/): run 42920329890 (commit 812a77d). In between, the first run of the hook form (run 42901650680) failed because the wait hook looked for a Cluster under a name the chart does not produce; the hooks now find it by its release label. PostgreSQL 18 on one kind node, linux/amd64 only |
| Chart install and upgrade on kind for nginx and the project template | projects runs 42868563456 and 42901650680 | linux/amd64 |
| PostgreSQL 16, 17 images with the extension test (pgvector example) | runs 42882522865, 42901650680 | — |
The platform chart on kind: install with the migration hook and least-privilege role check, helm test, upgrade, helm test again | infra runs 42915487605 (commit d00e5d2) and 42925002412 (commit 629ebdd), every job green | Earlier runs failed on configuration faults in the kind values and on the default-deny NetworkPolicy blocking the test pod; both fixed. linux/amd64, one node, development-grade values |
Rust format, clippy, the whole Rust test suite against PostgreSQL 18, migrations; web lint, typecheck, unit tests and build; generated-file staleness; buf lint; cargo-deny | ci green on every push since commit 7ce0cb7 (runs 42881955149, 42882523029, 42901650588, 42904755656) | These also ran locally |
| gitleaks, pnpm audit, cargo-audit, Trivy filesystem and configuration scans, CodeQL (TypeScript) | security green on every push since 7ce0cb7 | Results go to workflow artifacts and job summaries, not to code scanning (not enabled; ADR-0044). OpenSSF Scorecard and dependency review are skipped on a private repository |
Ran only locally (build sandbox)
| Item | Evidence |
|---|---|
Each project tree as a repository of its own (WP-83): exported outside the checkout as a git repository, then the project's own make validate build test scan sbom chart-test there for the base, the template and nginx; for Valkey the 9.1 line (Sentinel failover test included) and for PostgreSQL the 18 line; make validate and actionlint for all five. A check finds no file in any tree that refers outside it. The rule engine checks every tree with every rule, without exemptions | WP-83. For the base and nginx the same then passed on a GitHub runner, nginx with its chart installed on kind (projects, run 43083172187). Not run: the other version lines of Valkey and PostgreSQL after the restructuring, Valkey, PostgreSQL and the template on a runner in the new form, arm64 |
| With SELinux enforcing (the owner's Fedora machine): the Compose services after the bind mounts got the relabel option | reported by the owner as failing before the change; the change itself was checked only on a host without SELinux |
Repository stewardship (WP-80): onboarding through the App with the callback's binding rules, the rule engine over the template and every project tree, source backups against local bare repositories (bundle verified, manifest equal to for-each-ref, token never in arguments, URLs, errors, logs or stored rows), access reconciliation that never touches people CommonLayer did not add, succession by transfer and by restore with the successor rule, and the whole flow over HTTP with the development provider (acceptance workflows F, G and H) | WP-80: cargo test --workspace, 914 passed, 0 failed, 7 ignored, on the final tree (coordinator, 2026-11-11). The same suite then passed on a GitHub runner (ci, run 43028990763), so this item no longer ran only locally; the browser tests below still did |
The backend and worker images built from the final tree (make image-backend image-worker: release build inside the image's narrow build context, which is what failed in the nightly run). The worker image carries git 2.54.1 at /usr/bin/git and runs as uid 10001; the backend image has no git. Before that, the Dockerfile's git stage alone was run on the base image with a read-only root and the worker's cleared environment: ls-remote and fetch of a public repository over HTTPS, bundle create, bundle verify | coordinator, 2026-11-11. The three platform images were then built on a GitHub runner and the chart installed on kind (infra, run 43029000216). The containerised stack (make stack) was not started again after WP-80 |
| The portal for onboarding and stewardship in a browser against the development provider: connect, install, pick, scan with findings, fixing push, rescan, propose; repository administration; succession by restore; rule waiver and approval | WP-81: Playwright stewardship.spec.ts within the whole suite (1188 tests, 1076 passed, 112 skipped by design, 0 failed) |
The publish drill: nginx built with the project's scripts, pushed to the source registry, SBOMs, cosign signature and three attestations, submitted by a CI service-account token, verified, scanned with real Trivy and Grype databases, evaluated (15 image checks pass, 2 not applicable), mirrored through the registry's token authentication and promoted; anonymous pull by digest with a pull-only token; cosign verify and verify-attestation at the CommonLayer reference; SBOM download; the Helm chart promoted with chart.images_pinned and chart.schema; an unsigned image rejected and absent from the registry (404) | docs/status/WP-70g.md, transcripts var/drill/transcript-final-{1,2}.md (not committed); run twice, both exit 0, against an independent backend instance and the registry-alt registry (publish drill) |
| The whole Playwright suite: 1080 tests, 993 passed, 87 skipped by design, 0 failed (375/768/1280 px × light/dark, axe WCAG 2.2 AA) | WP-70e, against next start on :3000 and the seeded development backend |
The containerised stack (make stack, make stack-seed): database roles, migration as owner, every process healthy and read-only, least privilege confirmed by /readyz and commonlayer_db_privileged_connection 0, monitoring profile with all targets up | WP-70g |
Backup, restore and restore drill against the stack, as owner and runtime role (ledger sound, audit chain intact, object inventory complete); clctl secrets rotate on a restored copy | WP-70g |
The full platform images (commonlayer/{backend,worker,web}) built from the tree and scanned | WP-70g |
| Valkey's Sentinel failover test on all five lines, including a reproduction of the runner's slow-DNS condition | WP-70f locally; also green on GitHub: projects run 42932208078 (commit 63b4dca), job projects/valkey (amd64) — validate, build, tests including the Sentinel failover test, scan gate, SBOM, chart tests, and chart install and upgrade on kind all passed. Three earlier runs failed in the test setup (slow DNS answers on the runner, then two behaviours of the runner's Docker 28 that differ from Docker 29) |
make -C projects/<name> validate build test scan sbom chart-test for base, template, nginx, Valkey and PostgreSQL 18 with the declared-SBOM-component changes | WP-70f (PostgreSQL 16 and 17 were not rebuilt locally with that change; they passed on a runner) |
| Known-vulnerable demonstrations of declared SBOM components (nginx 1.25.3 and Valkey 8.0.1 fail the gate through Grype) | WP-70f |
| Development cookie relaxation in a browser | WP-70e's Playwright runs (the earlier WP-02 check was curl only) |
Implemented but partial, and open requests nobody picked up
Repository stewardship (WP-80, WP-81):
- The API process holds the GitHub App key as well as the worker, because the repository picker asks GitHub synchronously (threat model O16). The plan wanted it in the worker only.
- Backups hold git history only. Issues, pull requests, release pages, wikis and Git
LFS objects are not backed up; every manifest says so. A bundle is assembled in memory
before upload, bounded by
github.backup_max_bytes(2 GiB by default). - An accepted collaborator invitation is noticed at the next reconciliation, not when
it happens (the
memberwebhook is not processed). - The rule catalogue knows one template version. A second version needs versioned rule sets. First-party projects in this repository report their CI rules as not applicable, because this repository's workflows build them.
- Five of the new metrics are on no dashboard; the three alerts and their runbook sections exist.
- The development GitHub provider resolves concurrent writes to one repository by
last write wins, and reads its repositories from the checkout, so it works in
make devand in the Compose stack (checkout mounted) and nowhere else. - A release backup links to the release history, not to one release: the portal has no page per release.
- Verifying a restore needs
project.maintainers.manage. The successor creates the new repository; a project admin or a platform reviewer runs the verification. - The stewardship-hosted restore was never run end to end, in the portal or against GitHub: the development stack has no stewardship organization. Its service path is tested with wiremock and a local bare repository.
- The seeded RabbitMQ project was seeded in review directly, not through an
onboarding, so its repository link reads
pending; a project that comes through onboarding has a verified primary repository. - The project trees still live in this repository. They are complete repositories
(
projects/base,nginx,valkey,postgresql), exported unchanged byscripts/export-project.sh, and stay here untilcommonlayer-org/<project>exist. After that the trees, theprojectsworkflow,mk/projects.mkand the platform's local base image fallback are removed from this repository. - No base image is released, so nginx, Valkey and PostgreSQL have an empty
images[].base.digestand build from a base built out of a checkout of the base project. Their release workflows refuse to release until the digest is filled in.
Platform and backend:
- Platform binaries carry no dependency metadata. syft and Trivy see no Rust crate in
the platform images; only cargo-deny and cargo-audit in CI cover the Rust
dependencies. Request (WP-70g): build release binaries with
cargo auditable. commonlayer_build_inforeportscommit="unknown"in the images: the build passesVCS_REFas a label only. Request (WP-70g): pass the commit to the metric.- The bundled cosign 3.1.4 (worker image and
scripts/dev/install-tools.sh) contains golang.org/x/net 0.61.0 (CVE-2026-78661, HIGH, fixed in 0.62.0), go-chi/chi 5.3.2 (CVE-2026-114437, MEDIUM) and x/crypto 0.58.0 (GO-2026-5932). Request (WP-70g): update when a cosign release with the fixes exists. - The seed writes before it has read every manifest, so a failing seed leaves the
database marked
seed.partialand has to be reset. Request (WP-70g to WP-40). - No public list of organizations, so organization pages are not in the sitemap
(WP-70e). Also requested by WP-70e and not done:
GET /admin/maintenance/sla(the platform default SLA can be written but not read), usernames on payout runs and onupdated_byof settings, project slugs on ledger accounts and evaluation details, and a paginated public contributor list per project (first requested by WP-31). - Ledger and audit tamper resistance against the owner role or a superuser (threat model O1, O2): the runtime role cannot disable the triggers, but whoever holds the owner credentials can. Not done: a hash chain over the ledger, and exporting audit checkpoint digests outside the database.
- The API still holds the payment provider's secret key and the registry token signing key (O7): checkout, refunds and subscription changes are synchronous provider calls, and the token realm signs pull tokens. Moving provider calls into worker jobs and a separate promoter process are follow-ups.
- Repository links verified before migration 0016 are not re-checked against GitHub's numeric id (review MEDIUM-5).
- Areas the security review did not cover: registry retention and registry-event ingestion beyond authentication; the SBOM, VEX, Trivy and Grype parsers and the subprocess adapter; outbound webhook sending; organization role APIs and the last-admin trigger; password reset details (reset tokens issued before an email change stay valid, noted, not analysed); lockout and rate-limit internals; audit and log redaction coverage; the web content security policy and the development-only pages; gRPC parity for maintenance, security and artifact mutations; rounding in settlement beyond the largest-remainder approach. The review also did not run the test suites.
- Rate limiting during a Valkey outage is per process: N API replicas allow up to N times each limit (ADR-0019).
- Registry retention protects digests with open findings or named in a published
advisory (the security domain's
retention_protection, since WP-70g) and promoted digests with any present vulnerability; blobs are reclaimed only by Distribution's offline garbage collection. Retention was outside the security review. - OSV pagination beyond the first page is not followed; CVSS v4 vectors are not scored.
- Stripe: the
invoice_payment.paidevent must be enabled on the webhook endpoint; without it the link is resolved on demand (one API call per unmatched refund or dispute). A refund hold whose provider webhook arrives before the request stored the refund reference lapses after 7 days instead of being released. clctl registry verify-preservationran against the drill's registry, where 15 of 18 preserved digests are reportedmissing_manifest: the development seed records digests it never pushes.- gRPC has no RPC for operations that need an interactive session, and no
GRPCRoute; the chart exposes it through an Ingress with h2c to the pod (rendered, not installed). - Portal: three maintainer actions have API operations but no portal page, found
while writing the handbooks (not recorded in any status file): reviewing a community
contribution (
POST /contributions/{id}/review), submitting a contribution by hand (POST /projects/{slug}/contributions) and deciding a task waiver (POST /tasks/{id}/waivewith a decision). The platform default SLA editor starts from a project that uses it (no read API); "set back to the default" for a runtime setting stores the default as an override (no delete); theunknown-payout resolve dialog has not run end to end (no seeded unknown payout); contribution targets can be reported for abuse only through the API; ledger accounts and payout-run initiator/approver show ids, resolved on the page. - Compose stack: all portal traffic counts against the web container's address unless the stack trusts it (ADR-0040).
- Load: the musl allocator under multi-threaded load was not measured (WP-50 asked WP-70 to).
Images, charts, catalog and CI:
- Scanner coverage of source-built components rests on Grype alone: Trivy evaluates
none of the declared nginx, Valkey, PostgreSQL and darkhttpd components
(ADR-0039).
CommonLayer's own helpers (
cl-probe,cl-kube-label) have no vulnerability feed; Valkey's vendoreddeps/are not declared separately. - Requests of WP-70f to the CI owner not yet done: upload the SBOM-scan SARIF
(
sarif/trivy-sbom,sarif/grype-sbom) to code scanning when it is available (only the image-scan SARIF is uploaded); runmake -C projects/postgresql chart-test-kindinstead of thescripts/test-kind.shwrapper. Done in the workflows as they stand: the "Keep reports" step uploads hidden files,projects-rescaninstallssyft, and one tool installer is used everywhere. - The Valkey HA test and the PostgreSQL HA hooks, which failed on GitHub runners during this work, pass there now (runs 42932208078 and 42920329890; see above).
- Base image not released, so
images[].base.digestis empty in every manifest; the release order is inprojects/base/README.md. - Bitnami catalog: nginx, Valkey and PostgreSQL are
in_development(built and tested here, nothing published) (ADR-0042).
Decisions that belong to the operating entity
| Decision | Where it shows |
|---|---|
Creating the project repositories. The four first-party trees name commonlayer-org/<project> as registry source (ghcr.io/commonlayer-org/<project>) and signing identity (https://github.com/commonlayer-org/<project>/.github/workflows/*@refs/tags/v*). Until those repositories exist and the exported trees are pushed, nothing can be released or onboarded for real. Informational references in the platform still name a commonlayer organization: runbook URLs in the alert rules, the platform chart's image repositories, home and repositoryUrl, the default SOURCE_REPOSITORY build argument of the platform images (the release workflow passes the real one) and Compose's web REPOSITORY_URL | projects/*/commonlayer.yaml, scripts/export-project.sh, infrastructure/monitoring/prometheus/rules/commonlayer-alerts.yaml |
| Legal review of the privacy and terms pages, which are templates | apps/web/src/app/(public)/legal/ |
| Creating the GitHub App under the operating entity's account, with Administration: write on connected repositories, and accepting what that permission means | the GitHub App, threat model B10 |
| Whether funded projects must be connected at the managed level (default yes), and the grace period for a transfer (default 30 days) | runtime setting projects.require_managed_repository; projects.repository_transfer_grace_days |
| Whether to run a stewardship organization that can host a project continued from a backup | github.stewardship.*; without it the successor hosts the new repository |
| Legal review of maintenance agreement v2 (keep the App installed; transfer the repository on stepping back; continuation from the backup otherwise) | the seed's agreement text, crates/commonlayer-app/src/seed.rs |
| Security and conduct contacts (address, key, response targets, conduct team): until filled there is no monitored private channel | SECURITY.md, CODE_OF_CONDUCT.md |
| The Bitnami catalog's licensing rule (OSI-approved upstream licence required) | projects/bitnami-migration/README.md |
| The reward single-approval limit (default $100; two colluding members can reward a third account up to it, once per approved contribution; threat model O6) and whether a per-recipient cap is wanted | runtime setting funding.reward_single_approval_max_minor |
The not_affected confirmation threshold (default high) | runtime setting security.not_affected_confirmation_min_severity |
CODEOWNERS team handles (@commonlayer/* are placeholders) | .github/CODEOWNERS |
Repository variables: CL_BASE_IMAGE (released base by digest, required before the first platform release), CL_ARM64_RUNNER (arm64 on a private repository), in each project repository COMMONLAYER_API_URL (registration from its release workflow) and CL_BASE_REPOSITORY (the base project, while no base release exists) | repository settings |
| Enabling GitHub Code Security (or making the repository public) for code scanning, dependency review and Scorecard; required checks | repository settings |
| Recovery objectives (RPO, RTO) | disaster recovery |
| Payment provider, legal entity, tax handling, live payouts (all payout gates) | deployment, ledger specification |
State of the GitHub workflows (2026-11-11, after the push for the standalone projects)
The stewardship commits were pushed without workflow runs
(ADR-0048). The final push (0c3ffd0) then ran ci,
security and docs, and infra was started by hand for the same commit, because its
path filter only sees the last push. Scheduled workflows ran regardless of the markers.
The work after that (WP-82, WP-83) was pushed the same way; its final push (d6e382b) ran
ci, security and docs, and projects was started by hand for two trees.
| Workflow | Latest completed result | Notes |
|---|---|---|
ci | success (d6e382b, run 43083162371) | the tree with the standalone projects: format, build-context check, clippy, the Rust tests, migrations, cargo-deny, generated files, web lint, typecheck, unit tests and build, protobuf |
security | success (d6e382b, run 43083162441) | code scanning unavailable on this private repository |
docs | success (d6e382b, run 43083162454) | markdownlint, links, Mermaid |
infra | success (0c3ffd0, run 43029000216, started by hand), every job | the backend, worker and web images built on the runner and the platform chart installed, upgraded and tested on kind with migrations 0022 to 0025. Not run since: two migrations, the template files the backend embeds and the monitoring check's mount option changed after it |
projects | success (d6e382b, run 43083172187, started by hand for base and nginx) | the rewritten workflow: schema tests, template drift, the self-contained and bind-mount checks; then each tree exported outside the checkout and its own targets run there. nginx: base built from the exported base tree by the project's own script, validate, build, test, scan gate, SBOM, chart tests, chart install and upgrade on kind. base: validate, build, test, scan gate, SBOM. Not run in this form: Valkey, PostgreSQL and the template (their last runner results are from before the restructuring: runs 42932208078 and 42920329890) |
e2e | failure (e6d070e, scheduled run 42998340850): the backend image did not build, because template files the rule engine embeds were outside the image's build context | fixed in f35e8b2 with a check in the Rust lint step; the infra run above built the same images. The workflow has not run since and has never been green; the next nightly run is its first with the fix |
projects-rescan, projects-release | removed in WP-83 | releasing and rescanning belong to each project's own repository. projects-rescan ran once on schedule before (dad9320, run 43011850364) and scanned nothing, because nothing is published |
release, ops | no run recorded | — |
Acceptance workflows A–E
The product brief's five workflows, and what proves each. "Fakes at the boundary" means
the real composition (AppContext::assemble) over a real PostgreSQL database per test,
with fakes only for time, the source and destination registries, cosign, Trivy/Grype,
repository files, the Actions OIDC verifier and SMTP; the payment provider is the real
simulator with signed webhooks; jobs run through the real job registry.
| Workflow | Acceptance test (fakes at the boundary) | Real tools | Browser |
|---|---|---|---|
| A · Project onboarding | crates/commonlayer-app/tests/it/workflow_a_onboarding.rs: proposal, repository link and verification, review, manifest sync, treasury, assignments, CI submission over HTTP with an OIDC bearer, all 15 image checks and chart.images_pinned pass, promotion; an unsigned build is rejected and nothing is mirrored | The publish drill: real build, cosign (key pair), Trivy, Grype, syft, Helm, Distribution; submission by API token, not OIDC; manifest synced from a local file | Project administration specs (admin-pages, admin-project-flows) |
| B · Funding | workflow_b_funding.rs: organization, recurring checkout confirmed only by signed provider events, coverage and states, evaluation, settlement (primary 200, secondary 150, flexible 100, infrastructure 50 USD), public ledger, audit, verify_ledger, audit checkpoint. Also WP-14's fifteen-step scenario | Simulated provider only; no live Stripe | portal-funding.spec.ts (simulated checkout to confirmed receipt; guest status token; organization checkout) |
| C · Security remediation | workflow_c_remediation.rs: scheduled rescan finds a critical CVE, deadlines, notifications and mail, assessment, contributed fix, new revision promoted, finding resolved with the fixing digest and contribution, old digest still affected | The drill's scans ran real Trivy and Grype on the promoted digest; no remediation cycle with real tools | Maintainer and project security specs; the second-reviewer flow in wiring.spec.ts |
| D · Maintainer replacement | workflow_d_replacement.rs: paid March obligation, replacement on April 15, every ledger balance and the transaction count unchanged, April split 15/15 days. Also WP-13's no_financial_effect tests and WP-14's example 9 | — | admin-project-flows.spec.ts (replacement; public funding unchanged) |
| E · Consumer verification | workflow_e_verification.rs: search, three separate states, digest mapping, ES256 pull token with pull only, verification record, provenance, SBOM download, verify instructions, chart default image digest | The publish drill: anonymous docker pull by digest, cosign verify and verify-attestation (SLSA v1, SPDX, CycloneDX) at the CommonLayer reference, helm pull, unsigned image 404 | portal-catalog.spec.ts (artifact, version and digest pages) |
Not proven by any of these: keyless signatures, GitHub's provenance format, live payments and payouts, a GitHub App, and anything on a cluster.
Repository stewardship added three workflows of its own (plan 13 §10, §11):
| Workflow | Acceptance test | Real tools | Browser |
|---|---|---|---|
| F · Succession | workflow_f_succession.rs: the owner's assignment ends, the case opens with a backup, a transfer into the wrong hands is refused, a transfer to an appointed maintainer closes it; the restore path is verified against the backup; ledger balances and the transaction count are identical before and after | git against local bare repositories in the backup and restore tests; never github.com | stewardship.spec.ts: admin plans the restore of the seeded overdue case, a maintainer verifies the restored repository |
| G · Onboarding | workflow_g_onboarding.rs: installation bound only after GitHub lists it for the person, picker, scan fails on findings, fix, rescan passes, propose creates the project with the repository as verified primary; approval rules | The rule engine runs over this repository's template and projects (repository_rules.rs) | stewardship.spec.ts: connect, install, pick, findings, fixing push, rescan, propose |
| H · The same over HTTP with the development provider | workflow_h_dev_github.rs: install redirect, development installation, callback, paged picker, findings, simulated push, rescan, propose; another person's installation and a non-administrator are refused; a successor-hosted restore completes and a non-maintainer's is refused | — | the browser tests above run against this provider |
Test inventory
Counts as recorded in the status files; the date of every run is 2026-11-10.
| Suite | Count | Where it ran |
|---|---|---|
Rust workspace (cargo test --workspace) | 926 passed, 0 failed, 7 ignored (full local run of 2026-11-12, coordinator) | locally; ci / rust on a GitHub runner last for the tree before WP-90 (run 43083162371) |
| of which acceptance workflows A–E and the seed test | 5 + 1 (commonlayer-app integration tests: 25 in total at WP-70g) | locally and on runners |
| of which gRPC | 8 unit + 25 integration (WP-41), plus pull_statistics_over_grpc (WP-70b) | locally and on runners |
| of which hardening and review regressions | every finding of the review has a named regression test except LOW-1, whose refusal is not separately asserted (docs/status/WP-70b.md) | locally and on runners |
| Ignored Rust tests | manual real-scanner tests (real_scan, installed_scanners) and doc examples; the real-scanner tests passed when run by hand (WP-12) | locally |
| Web unit and component tests (Vitest) | 271 passed (WP-90) | locally; ci / web on a GitHub runner last for the tree before WP-90 (run 43083162371) |
| Playwright | 1902: 1312 passed, 590 skipped by design, 0 failed (WP-90, on a fresh seed with the development GitHub provider; the count grew with the rule check over 117 page types at two widths) | locally only; the e2e workflow has never been green on a runner |
| Platform chart | helm lint ×5, kubeconform ×10 (Kubernetes 1.31 and 1.37), helm-unittest 66/66, trivy config clean (WP-80) | locally; infra / chart on a GitHub runner for the final tree (run 43029000216) |
| Monitoring | promtool: 22 rules with unit tests; metric references: 139 expressions, 88 metrics (84 catalog, 4 Distribution) (WP-70g) | locally; infra / monitoring on runners |
| Image and chart projects | base: 51 project checks; nginx: 30 per line, 33 chart unit tests; Valkey: 570 ok checks over 5 lines, 73 chart unit tests; PostgreSQL 18.6: 101 ok checks, 45 + 31 chart unit tests; template: 31 chart unit tests (WP-70f) | locally; on runners as listed above |
| Manifest schema | 4 valid, 26 invalid manifests; template drift 81 files, 4 projects | locally and on runners |
| Bitnami catalog | 20 candidates, 0 problems; kubeconform and jsonschema 20/20 | locally and on runners |
| Publish drill | 2 runs, exit 0 | locally |
| k6 | smoke profiles of browsing, search and registry token | locally (WP-50) |
| Documentation | markdownlint 0 findings; every relative link and anchor resolves; every Mermaid block parses (WP-70h) | locally; docs on runners (links and Mermaid green, markdownlint red before WP-70h) |
Status by work package
| WP | Title | Status | Report |
|---|---|---|---|
| WP-01 | Foundation: workspace, kernel, schema, dev environment | done | WP-01 |
| WP-02 | Identity, organizations, API skeleton | done | WP-02 |
| WP-10 | Projects | done | WP-10 |
| WP-11 | Artifacts and registry | done | WP-11 |
| WP-12 | Security | done | WP-12 |
| WP-13 | Maintenance and eligibility | done | WP-13 |
| WP-14 | Funding and ledger | done | WP-14 |
| WP-15 | GitHub and notifications | done | WP-15 |
| WP-20 | Project template, base image, nginx | done; release workflow never run | WP-20 |
| WP-21 | Valkey | done; green on a GitHub runner (run 42932208078) | WP-21 |
| WP-22 | PostgreSQL (single and HA) | done; HA test green on a runner in its hook form (run 42920329890) | WP-22 |
| WP-23 | Bitnami migration catalog | done; three entries in_development | WP-23 |
| WP-30 | Web shell and design system | done | WP-30 |
| WP-31 | Public portal | done (gaps closed by WP-70e) | WP-31 |
| WP-32 | Authentication pages and dashboards | done (gaps closed by WP-70e) | WP-32 |
| WP-33 | Project and platform administration | done (gaps closed by WP-70e) | WP-33 |
| WP-40 | Integration, seed, acceptance tests | done | WP-40 |
| WP-41 | gRPC | done | WP-41 |
| WP-50 | Deployment, CI, monitoring | done; kind job green on runners (runs 42915487605, 42925002412) | WP-50 |
| WP-60 | Documentation and ADRs | done; revised by WP-70h | WP-60 |
| WP-70a | Backend hardening | done | WP-70a |
| WP-70b | API gaps and review fixes | done | WP-70b |
| — | Independent security review (19 findings) | all fixed | review |
| WP-70d | CI from real runs | done; see workflow state above | WP-70d |
| WP-70e | Web follow-ups and full e2e | done | WP-70e |
| WP-70f | SBOM, catalog and project pipelines | done; the two runner failures were fixed (runs 42920329890, 42932208078) | WP-70f |
| WP-70g | Deployment and the publish drill | done | WP-70g |
| WP-70h | Final documentation pass | done | WP-70h |
| WP-80 | Repository stewardship: App onboarding, rule engine, source backups, managed access, succession, development GitHub provider | done; never against github.com | WP-80 |
| WP-81 | Portal: onboarding and stewardship pages | done | WP-81 |
| WP-82 | Missing bucket named as such; a project directory as a development repository; GitHub App key by file; App registration helper | done | WP-82 |
| WP-83 | Every project is its own repository: standalone trees, export, no exemptions in the rule engine | done locally; the repositories do not exist yet | WP-83 |
| WP-90 | Portal reworked by "don't make me think"; invitations and reward approvers in the API; webhook processing without a second connection | done | WP-90 |
Feature areas
Foundation
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
Workspace, lints (unsafe_code forbidden, unwrap/expect denied outside tests), cargo-deny, cargo-audit | done | Cargo.toml, clippy.toml, deny.toml, .cargo/audit.toml | clippy; cargo-deny and cargo-audit locally and in CI | one justified ignore (RUSTSEC-2026-0459, SQLite driver never compiled), review by 2027-01-31 |
Kernel: ids, Money with largest-remainder allocation, Digest, Period, Clock, errors, pagination | done | crates/commonlayer-core/src/ | unit and property tests | curated table of 32 currencies |
Permission matrix, Actor, token scopes, never-by-token set, human-only set | done | crates/commonlayer-core/src/authz/ | literal matrix test, service_accounts_never_hold_human_only_permissions | ADR-0035 |
Crypto: SecretBox v2 with key ids, keyring and re-sealing; token hashing; HMAC | done | crates/commonlayer-core/src/crypto.rs, clctl secrets rotate | RFC 4231 vector, tamper tests, rotation tests; rotation run on a restored copy (WP-70g) | — |
| Configuration with validation, redaction and per-process loading | done | crates/commonlayer-config/ | cargo test -p commonlayer-config | production refuses the simulator, a non-__Host- session cookie, http URLs, missing secrets |
| Metric catalog, JSON logging with trace and span ids, OTLP, Sentry error layer, ops server | done | crates/commonlayer-observability/ | staleness test of metrics.md, redaction tests | no trace store shipped; Sentry sends errors only |
Schema (18 migration files, version 21, 121 tables at WP-70a's make db-check) and database invariants | done | crates/commonlayer-database/migrations/ | make db-check; invariant and role tests | — |
Runtime database role and clctl db check-role | done | crates/commonlayer-database/src/roles.rs, apps/cli/src/ops.rs | roles::*; stack and restore drill | owner or superuser can still disable triggers (ADR-0036) |
| Job queue, outbox, scheduler, idempotency store | done | crates/commonlayer-database/src/ | job, outbox and scheduler tests | throughput not load-tested |
Audit recorder, hash-chain checkpoints, clctl audit verify | done | crates/commonlayer-audit/ | audit tests; drill and stack runs | checkpoints live in the same database (O2) |
| SSRF-safe client | done | crates/commonlayer-net/ | blocked ranges, redirects, rebinding, limits | ignores proxies by design, so nothing outbound was exercised from the sandbox |
| Development environment | done | docker-compose.yml, scripts/dev/, mk/ | make up, make dev-backend, make seed used by every later package | MinIO image from Chainguard |
Identity and organizations
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Registration, verification, login, lockout, enumeration resistance, password reset and change, email change | done | crates/commonlayer-auth/src/service/ | accounts::*, sessions::*; Playwright wp32/auth.spec.ts | usernames are public by design; reset tokens issued before an email change stay valid (noted by the review) |
Sessions (__Host- cookie required outside development), CSRF, API tokens, service accounts (created only by a person in a session) | done | crates/commonlayer-auth/ | sessions::*, tokens::*, authz::* | — |
| GitHub OAuth and generic OIDC, state bound to the browser (HIGH-6) | done | src/service/oauth.rs, src/http/cookies.rs | wiremock provider; oauth::a_callback_is_accepted_only_in_the_browser_that_started_the_login | never against real GitHub |
| Rate limiting with per-process fallback; client address only behind trusted proxies | done | src/adapters/rate_limit.rs, src/http/middleware.rs | rate_limits::* (real Valkey), stack checks with forged headers | per-process limits during an outage |
| Organizations, members, invitations, billing profiles, notes; public funding totals | done | crates/commonlayer-organizations/, crates/commonlayer-funding/src/service/read.rs | integration tests; wp70::organization_checkout_covers_… | no public organization list |
| Abuse reports: intake, own list, admin queue, assign, resolve (not by the reporter) | done | crates/commonlayer-organizations/src/service/abuse.rs, migration 0021 | organizations/tests/it/abuse.rs; Playwright abuse flow | contribution targets only through the API |
Projects
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Lifecycle, derived funding, security and lifecycle states (thresholds from runtime settings) | done | crates/commonlayer-projects/src/domain/, src/service/derived.rs | table-driven tests; refresh::coverage_thresholds_follow_the_runtime_settings | no withdraw or un-deprecate; no per-project threshold overrides |
| Search with facets and keyset pagination | done | src/repo/search.rs | search::* | facets on the first page only |
| Manifest validation, sync, repository verification with the numeric GitHub id check | done | src/domain/manifest.rs, src/adapters/mod.rs, src/service/repositories.rs | conformance over every repository manifest; wiremock | never against GitHub; links verified before 0016 not re-checked; plain git repositories cannot be read |
| Declared SBOM components in the manifest model | done (carried only) | src/domain/manifest.rs (build.components) | declared_sbom_components_are_optional_and_typed | the platform stores the field; generation happens in project CI |
| Members, project service accounts, follows, migration candidates, catalog sync | done | src/service/, crates/commonlayer-auth/src/service/project_service_accounts.rs | members::*, tokens::project_service_accounts, catalog loads 20 candidates | — |
Artifacts and registry
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Verification policy (17 checks), waivers, project tightening; only the count of blocking findings on public pages (MEDIUM-7) | done | crates/commonlayer-artifacts/src/domain/policy.rs | pass and fail case per check; drill | — |
| Submission pipeline, resumable; resume re-runs scan and evaluation (MEDIUM-2); release-shaped tags of other versions refused (MEDIUM-1) | done | src/service/pipeline.rs, src/service/submissions.rs | pipeline tests with fakes; hardening::*; the drill with real tools | — |
| cosign adapter | done | src/adapters/cosign.rs | real cosign 3.1.4 key pair (WP-11, drill) | keyless never run |
| Verify instructions (key or keyless, with the right note) | done | src/domain/instructions.rs | instructions::tests; drill | the commands assume a transparency-log entry; the drill's key-signed artifacts also need --insecure-ignore-tlog=true |
| OCI client, mirror with referrers through the tag schema | done | crates/commonlayer-registry/src/adapters/ | real mirror test; drill | GitHub's referrers-API attestations not tested (O11) |
| Registry token endpoint (rate-limited per IP), key rotation, JWKS | done | src/service/token.rs | real registry accepts and refuses tokens; drill | — |
Registry events, pull statistics (GET …/artifacts/{name}/pulls, gRPC GetPullStats), preservation checks, retention | done | src/service/ | events, preservation, retention and pull-statistics tests | offline GC needed (advisory-only digests are protected since WP-70g: retention::a_digest_named_in_a_published_advisory_is_kept) |
Security
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Trivy, Grype and OSV adapters; subprocess rules | done | crates/commonlayer-security/src/adapters/ | captured fixtures; real scanner runs (manual tests, drill) | OSV first page only; CVSS v4 not scored; parsers not covered by the review |
| Ingestion, resolution, digest isolation, deadlines, KEV escalation, permanent breaches | done | src/service/ingest.rs, src/domain/ | ingestion::*, sla::* | — |
| Assessments, OpenVEX import and export, exceptions (decided by a person other than the requester) | done | src/service/triage.rs, src/domain/vex.rs | vex::*, exception lifecycle, confirmations::a_service_account_cannot_decide_an_exception | — |
Second reviewer for not_affected at or above the threshold | done | src/service/confirmations.rs, migration 0015 | confirmations::*; Playwright | below the threshold one person decides (ADR-0037) |
| Feeds (EPSS, KEV, OSV refresh, NVD) | done | src/adapters/feeds.rs | recorded responses | never against real hosts |
| Advisories, encrypted private reports (any key of the keyring decrypts), incidents | done | src/service/{advisories,reports,incidents}.rs | visibility tests for every role | — |
Maintenance and eligibility
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Eligibility engine with explanations, finalization, appeals, overrides (session only) | done | crates/commonlayer-maintenance/src/domain/eligibility/, src/service/eligibility.rs | unit and property tests, eligibility::*, human_decisions::* | rule set version 1; no appeal withdrawal |
| Assignments, replacement without financial effect, occupancy | done | src/service/assignments.rs | assignments::*, no_financial_effect::*, workflow D | hand-overs take effect now or earlier in the current month |
| Applications, profiles, agreements (text published and served), suspensions (listed), SLA versions, platform default SLA (write only) | done | src/service/{profiles,sla,listings}.rs | wp70::* | no read of the platform default SLA |
| Tasks with generation, waivers (decided by a person), public task list without private evidence | done | src/service/tasks.rs, src/service/listings.rs | tasks::*, wp70::the_public_task_list_hides_private_evidence_and_waiver_reasons | security-acknowledgement tasks are left out of the public list |
| Community contributions, review by a person, contributor role, tracked pull requests | done | src/service/contributions.rs, crates/commonlayer-app/src/reactions.rs | contributions::*, seams::* | only merged PRs by non-bot authors become contributions |
Funding and ledger
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Ledger posting with idempotency and ordered locks | done | crates/commonlayer-funding/src/ledger.rs | ledger::*, properties | owner or superuser can rewrite (O1) |
| Settlement and cycles (finance lock before reading eligibility, MEDIUM-6) | done | src/domain/settlement.rs, src/service/cycles.rs | worked examples, property tests, hardening::settlement_reads_eligibility_under_the_finance_lock | a failing cycle stays open and is retried |
| Contributions, receipts, fees, subscriptions, webhooks; guest status token | done | src/service/{contributions,webhooks}.rs | duplicate, reordered and concurrent delivery tests; wp70::a_guest_follows_their_payment_with_the_status_token | — |
| Providers: none, simulated (development and test only), Stripe, bank transfer (references used once) | done | src/adapters/ | Stripe fixtures and mock server | no live Stripe; payment_methods unused |
| Refunds with holds, dispute waterfall, provider withdrawals applied once, invoice-payment linking | done | src/service/webhooks.rs, src/domain/waterfall.rs | stripe::*, hardening::* | see Stripe limits above |
Obligations, payout runs with gates, unknown payouts and resolution, destination fixed at planning | done | src/service/{obligations,payouts}.rs | payouts::*, hardening::* | live payouts only against a mock (ADR-0041) |
| Rewards: proposer never approves, one per contribution, people only | done | src/service/rewards.rs | hardening::a_proposer_never_approves_and_a_contribution_is_rewarded_once | O6 residual (ADR-0045) |
Reconciliation, clctl ledger verify (also --remote over gRPC) | done | src/service/reconciliation.rs | reconciliation::*; drill, stack and restore drill | provider balance check only with Stripe |
GitHub and notifications
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Webhook intake, delivery store, processing; push to default branch syncs the manifest | done | crates/commonlayer-github/ | signature, redelivery, retry tests; seams::* | never against GitHub |
| Actions OIDC verification, workload actor on submissions | done | src/adapters/oidc.rs, crates/commonlayer-app/src/workload.rs | locally generated keys; seams::actions_oidc_bearers_become_workload_actors | no real token verified |
| Notifications: rules, templates, in-app, SMTP, signed outbound webhooks, GitHub channel; public event-kind list | done | crates/commonlayer-notifications/ | every template rendered, Mailpit, SSRF rejection, event_kinds_are_listed_publicly_from_the_rules_table | English only; at most 10 endpoints per owner; send-time behaviour not reviewed |
Repository stewardship and onboarding
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Onboarding through the GitHub App: install redirect with single-use state, callback that binds only what GitHub confirms and decides once, identity link, paged repository picker, onboardings, propose | done | crates/commonlayer-github/src/service/onboarding.rs, crates/commonlayer-app/src/stewardship_http.rs | stewardship::the_callback_binds_only_installations_github_lists_for_the_person, stewardship_review::*, workflows G and H | never against github.com |
| One rule engine for the onboarding scan and the guardrail check: 43 rules, static reads only, results with rule, standard, file and line; required rules, declared deviations, public waivers | done | src/domain/rules/, src/service/scans.rs | rules.rs (a failing case per rule, hostile files), repository_rules.rs (template and every first-party project comply) | one template version; first-party CI rules not applicable |
| Access levels and managed access: collaborators invited and removed for appointed maintainers only, stale logins refused by account id | done | src/domain/{access,reconcile}.rs, src/service/access.rs | exhaustive reconciliation test; access_is_reconciled_without_touching_people_commonlayer_did_not_add | invitation acceptance seen at the next reconciliation |
| Source backups: verified git bundle of every branch and tag with a manifest, release binding, retention, signed download with restore commands | done | src/adapters/{git,subprocess}.rs, src/service/backups.rs | bundle and manifest tests, token-leak tests, size and time limits | no LFS, issues or pull requests; bundle assembled in memory |
| Succession: automatic and manual opening, transfer only into appointed hands, restore planned by a platform reviewer and verified against the backup, primary switch | done | crates/commonlayer-projects/src/service/succession.rs, src/domain/succession.rs | projects::succession::*, stewardship_review::*, workflow F | stewardship-hosted restore never pushed to github.com |
| Approval rules: managed level, finished scan, no failing required rule unless waived | done | crates/commonlayer-projects/src/service/succession.rs (check_stewardship_for_approval) | approval_fails_closed_without_a_finished_scan, workflows A and G | — |
| Events, notifications, metrics, alerts, runbooks | done | crates/commonlayer-core/src/events/, infrastructure/monitoring/ | notification catalogue tests, make monitoring-check | five metrics on no dashboard |
| Development GitHub provider and its routes | done (development and test only) | crates/commonlayer-app/src/{devkit_github,dev_github_http}.rs, migration 0025 | workflow H; the_development_github_is_refused_outside_development_and_test | last write wins; needs the checkout |
| Portal: onboarding, repository administration, public maintenance panel, succession queue, waivers, development installation page | done | apps/web/src/features/stewardship/, apps/web/src/app/dashboard/onboarding/, apps/web/src/app/admin/successions/ | stewardship.test.tsx, stewardship.spec.ts | see WP-81 |
gRPC
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| 12 services, 59 RPCs, health, reflection, error details, shared rate-limit buckets, metrics | done | proto/commonlayer/v1/, crates/commonlayer-grpc/ | 8 unit + 25 integration + pull statistics; manual run with generated clients | API tokens only; no session-only operations; grpcurl was not available for the manual run (gRPC API) |
Web portal
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Shell, design system, documentation section, SEO, CSP | done | apps/web/src/ | Vitest; Playwright | — |
| Public portal: catalog, project pages, artifact/version/digest pages with pull statistics, security centre, funding transparency, contribution flow (guest status token, organizations), maintainers, organization profiles with totals, Bitnami catalog | done | apps/web/src/app/(public)/ | portal-*.spec.ts, wiring.spec.ts | organization pages not in the sitemap |
| Authentication pages and dashboards (user, organization, maintainer) | done | apps/web/src/app/(auth)/, app/dashboard/ | wp32/*.spec.ts | — |
| Project administration and platform administration (including abuse queue, settings registry, unknown payouts, suspensions, agreements) | done | app/dashboard/projects/, app/admin/ | admin-*.spec.ts | see the portal limits above |
| Legal pages | templates | app/(public)/legal/ | smoke | unreviewed by counsel |
| "Don't make me think" (plan 15): attention lists from real data on the dashboard, in project and platform administration; steps for onboarding; use-first project page; one navigation per context; destructive actions in a danger zone | done | src/features/attention/, src/components/domain/{next-step,steps,disclosure,danger-zone,status-list}.tsx | e2e/ux-rules.spec.ts (117 page types at 1280 and 375 px: one filled button at most, no destructive control in a page header, at most seven navigation entries per level, a word budget before the first data), e2e/attention.spec.ts, unit tests of the attention rules | long pages that pass the check but were not restructured: maintainer tasks, project funding administration, payouts, the verification guide. The check counts and measures; whether a page is self-evident still needs a person to look |
Images, charts and template
| Project | Status | Tests | Outstanding / limitations |
|---|---|---|---|
schemas/commonlayer-v1.schema.json (with build.components) | done | 4 valid, 26 invalid manifests | — |
Base image (projects/base), rebuilt BusyBox, cl-probe with its SBOM declaration | done | 51 project checks; green on runners | not released |
| Project template | done | make validate build test scan sbom chart-test; kind on runners | release workflow never run |
| nginx 1.30.6, 1.31.8 | done | 30 checks per line, 33 chart unit tests; kind on runners | HTTP/3 only the QUIC listener verified |
PostgreSQL 18.6, 17.11, 16.15; postgresql and postgresql-ha charts | done | see above | HA hook failed on its last runner run |
| Valkey 9.1.3, 9.0.7, 8.1.11, 8.0.12, 7.2.15; chart with standalone, replication, Sentinel | done | 570 ok checks locally | amd64 only; all steps including the HA test and kind passed on a runner (run 42932208078) |
| Scan results (Trivy 0.76.2, Grype 0.121.3, databases of 2026-11-10) | — | every image passes the critical gate; Grype suppresses CVE-2025-60876 by the base VEX, and Valkey 8.0/7.2 NVD backport ranges by the Valkey VEX | coverage limits in ADR-0039 |
| Bitnami migration catalog | done | catalog validation | three entries in_development |
Platform deployment, CI and operations
| Feature | Status | Implementation | Tests | Outstanding / limitations |
|---|---|---|---|---|
| Platform images (backend, worker with cosign/Trivy/Grype, web) | done | infrastructure/docker/ | built and scanned locally (WP-70g) | arm64 never built; Rust crates invisible to scanners; cosign CVEs |
Compose stack (make stack, stack-seed, stack-monitoring) with database roles | done | docker-compose.yml, mk/infra.mk | locally (WP-70g) | — |
| Platform Helm chart (roles, per-process secrets, gRPC exposure, trusted proxies, NetworkPolicies) | done (static) | infrastructure/helm/commonlayer/ | lint, kubeconform, 63 unit tests; kind install reached deployed once | kind job never green; never on a real cluster |
| OpenTofu modules (AWS object storage, database, cache) | validated | infrastructure/terraform/ | tofu validate, tflint | never planned or applied |
| Monitoring: 22 alerts, dashboards, collector | done | infrastructure/monitoring/ | promtool unit tests; Prometheus in the stack | every alert has a runbook section |
| Operations scripts: backup, restore, restore drill, preservation | done | scripts/ops/ | locally against the stack (WP-70g) | — |
| Workflows (10) | see the workflow state above | .github/workflows/ | actionlint, shellcheck | release workflows never run |
Documentation
| Feature | Status | Implementation |
|---|---|---|
| README, CONTRIBUTING, SECURITY and CODE_OF_CONDUCT (contacts are placeholders) | done | repository root |
| Architecture, API (REST and gRPC), security (threat model, privacy rules, verification policy, review report), funding, handbooks, guides, operations | done | docs/ |
| 45 architecture decision records | done | decisions |