Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ jobs:
# case the suite adds or a rule the authority core changes reaches accounts on
# its next pull request, never silently on the next re-pin. The same suite at
# the pinned revision runs with accounts' tests in the quality phases.
# Before the suite, the declaration gate (`module-package
# verify-host-interfaces`): every interface version module.codefly.yaml
# declares is the version that interface publishes at the pinned authority
# revision, or a patch below it within the same major.minor, so a declaration
# names no suite the pin did not run.
host-interface-conformance:
name: Host interface conformance (authority main)
runs-on: ubuntu-latest
Expand All @@ -380,10 +385,12 @@ jobs:
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: "1.27.3"
cache-dependency-path: module/services/accounts/code/go.sum
cache-dependency-path: |
module/services/accounts/code/go.sum
module/tools/go.sum
- name: Install Codefly
run: bash scripts/ci/install-codefly.sh
- name: Run the shared suite at authority main against accounts
- name: Hold the declared interface versions to the pin, then run the shared suite at authority main against accounts
run: bash scripts/ci/host-interface-conformance-main.sh

marketing:
Expand Down
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ Skills in `.claude/skills/`, loaded when the task calls for them:
module verification job, authorization coverage, the release-gate contract,
interface docs and story tests, the kit's version, marketing isolation, the
SDK boundary, the immutable module package, the scoped pools' database
authority, and the shared host-interface conformance suite at authority main. [RELEASE_GATES.md § Repository-specific
authority, and the shared host-interface conformance suite at authority main
with the declared interface versions held to the pinned suite. [RELEASE_GATES.md § Repository-specific
gates](./RELEASE_GATES.md#repository-specific-gates) says what each runs, and
`release-gates.test.mjs` holds this prose to the enforced set.
- More checks run as *steps* inside the `base-integrity` job than as gates of their
Expand Down
4 changes: 2 additions & 2 deletions RELEASE_GATES.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ no per-track exemption.
| `authz-coverage` | required | required | RBAC, audit, and no-broadening |
| `release-contract` | required | required | this gating graph itself |
| `docs-sync` | required | required | interface docs and story tests |
| `host-interface-conformance` | required | required | the shared host-interface suite at authority main |
| `host-interface-conformance` | required | required | the shared host-interface suite at authority main, and the declared interface versions held to the pin |
| `kit-version` | required | required | published frontend kit version vs. content |
| `marketing` | required | required | marketing isolation build |
| `sdk-boundary` | required | required | Codefly SDK boundary and contracts |
Expand Down Expand Up @@ -445,7 +445,7 @@ reverse, fails the `release-contract` job.
| `authz-coverage` | the generated authorization catalog: RBAC coverage, audit coverage, and permission no-broadening against `main` | `node module/tools/authz-coverage-gate.mjs`, plus `go test` for the gateway header-lockstep and adapter enforcement tests |
| `release-contract` | this gating graph itself, and the Dependabot configuration that feeds it | `node --test scripts/ci/release-gates.test.mjs`, `node --test scripts/ci/dependabot-coverage.test.mjs`, `node scripts/ci/release-gates.mjs check`, `node scripts/ci/dependabot-coverage.mjs check` |
| `docs-sync` | the generated interface docs and the story-trace tests (#516) | `node module/tools/interface-docs-gate.mjs check`, `node module/tools/story-trace-gate.mjs tests` |
| `host-interface-conformance` | accounts serves the host interfaces (authority, composition, installation) exactly as the shared conformance suite of `codefly-dev/authority` states them, at authority's main whenever main contains the pinned revision, so a case authority adds reaches accounts on its next pull request | `bash scripts/ci/host-interface-conformance-main.sh`, which re-pins the authority libraries to main when main contains the pin and runs `go test -run '^TestAccountsPassesTheHostInterfaceConformanceSuite$' ./pkg/adapters` |
| `host-interface-conformance` | accounts serves the host interfaces (authority, composition, installation, session, artifact) exactly as the shared conformance suite of `codefly-dev/authority` states them, at authority's main whenever main contains the pinned revision, so a case authority adds reaches accounts on its next pull request; and every interface version `module.codefly.yaml` declares is the version that interface publishes at the pinned authority revision, or a patch below it within the same major.minor, so a declaration names no suite the pin did not run | `bash scripts/ci/host-interface-conformance-main.sh`, which resolves the pinned authority commit in its clone of main (fetching it by full id when main does not contain it), runs `go run ./cmd/module-package verify-host-interfaces` (in `module/tools`) over its `interfaces/` tree, then re-pins the authority libraries to main when main contains the pin and runs `go test -run '^TestAccountsPassesTheHostInterfaceConformanceSuite$' ./pkg/adapters` |
| `kit-version` | the published frontend kit's version moves whenever its content does, since a registry version is immutable once served | `node --test scripts/ci/kit-version.test.mjs`, `node scripts/ci/kit-version.mjs check` |
| `marketing` | the marketing runtime builds in isolation from the app, and the public config is current | `node module/tools/generate-public-config.mjs --check`, `node module/tools/marketing-extraction.mjs` |
| `sdk-boundary` | the root module's own tests, the Codefly SDK boundary, single-invocation protocol generation, the exported API contract, and the published module-authority client against the real host | `go test ./...` **in the root module only**, `go test codefly_sdk_boundary_test.go`, `codefly generate contracts saas-starter --check`, `codefly generate runnables saas-starter --check`, `go test ./...` in `qualification/module-authority` |
Expand Down
2 changes: 1 addition & 1 deletion module/module.codefly.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ interface:
- codefly.dev/authority@0.3.5
- codefly.dev/composition@0.2.0
- codefly.dev/installation@0.4.0
- codefly.dev/session@0.2.0
- codefly.dev/session@0.2.1
- service: auth-gateway
endpoint: grpc
visibility: internal
Expand Down
46 changes: 41 additions & 5 deletions module/services/accounts/HOST_INTERFACE.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# The host interfaces, served by accounts

accounts implements the host interfaces published by `codefly-dev/authority`:
`codefly.dev/authority@0.3.5`, `codefly.dev/composition@0.2.0`,
`codefly.dev/installation@0.3.0` and `codefly.dev/session@0.2.0`. The local
authority implements the same four on a laptop. The shared conformance suite
(`libraries/conformance/go`) proves that the two agree.
`codefly.dev/artifact@0.1.0`, `codefly.dev/authority@0.3.5`,
`codefly.dev/composition@0.2.0`, `codefly.dev/installation@0.4.0` and
`codefly.dev/session@0.2.1`, as `module/module.codefly.yaml` declares them. The
local authority implements the same five on a laptop. The shared conformance
suite (`libraries/conformance/go`) proves that the two agree, and the
declaration gate (`module-package verify-host-interfaces`, under Proof below)
holds each version named here and in the manifest to the version the interface
publishes at the authority revision `go.mod` pins.

## One authority core, two thin hosts

Expand Down Expand Up @@ -156,7 +160,39 @@ behavior-preserving rollback.
- `.github/workflows/ci.yml` (`host-interface-conformance`, the required
context "Host interface conformance (authority main)" and a release gate)
runs the suite at authority main, whenever main contains the pinned revision,
on every pull request and merge-queue entry.
on every pull request and merge-queue entry; the same suite at the pinned
revision runs with accounts' tests in the Codefly quality phase.
- Before that suite, the same job runs the declaration gate, `module-package
verify-host-interfaces` (in `module/tools`, with its own tests in
`modulepackage/host_interfaces_test.go`). It reads
`interfaces/<name>/interface.codefly.yaml` at the pinned authority commit,
resolved in the clone the job already makes (a pin on an unmerged authority
branch is fetched by its full id instead), and refuses: a version
`module/module.codefly.yaml` declares above the one published there (a
claim no suite proved); a version in another major.minor than the published
one (passing 0.5.0's suite runs no 0.4.0 suite); an interface the pin does
not publish; authority libraries pinned at two revisions, replaced or
excluded (`go.mod` pins the suite, the core it decides with, the client,
delivery and resources at one commit, and the require line must be what
runs); and an opening sentence of this document naming another version than
the manifest. A declared patch below the published one, within the same
major.minor, is a notice, never a failure: the pin may move to run a newer
patch's suite before the declaration follows it, and the declaration never
moves first. The half that needs no network, one revision in `go.mod` and
this document agreeing with the manifest, also runs with the `module/tools`
tests in the module-package job.
- Last recorded run: authority `dea37afac9ad` (its main on 2026-10-30, the
revision `go.mod` pins for all five authority libraries), from
`module/services/accounts/code`, on 2026-11-03:

GOWORK=off go test -count=1 -timeout 30m -run '^TestAccountsPassesTheHostInterfaceConformanceSuite$' -v ./pkg/adapters

passed 94 cases (the shared suite, the solution-principal target and the
cases beyond the suite, as `go test -v` lists them one level under the
test), 294 subtests at every depth; failed 0; skipped 0; 74 s. The
admission-key case ("only the hop registers an admission key, published
apart from the Work Context keys") is among them, with the fixture's
`HopCredential`. The section below carries no red line from this run.
- The core's store contract (`authority-core/go/storetest`) runs against this
Postgres store in `pkg/infra/postgres_authority_core_test.go`.
- The core's own decisions are unit tested in `codefly-dev/authority`.
Expand Down
4 changes: 2 additions & 2 deletions module/services/accounts/code/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ require (
github.com/codefly-dev/authority/libraries/authority-client/go v0.1.1-0.20261030222015-dea37afac9ad
github.com/codefly-dev/authority/libraries/authority-core/go v0.0.0-20261030222015-dea37afac9ad
github.com/codefly-dev/authority/libraries/conformance/go v0.0.0-20261030222015-dea37afac9ad
github.com/codefly-dev/authority/libraries/delivery/go v0.0.0-20261028224835-f82a98e093ef
github.com/codefly-dev/authority/libraries/resources/go v0.0.0-20261028224835-f82a98e093ef
github.com/codefly-dev/authority/libraries/delivery/go v0.0.0-20261030222015-dea37afac9ad
github.com/codefly-dev/authority/libraries/resources/go v0.0.0-20261030222015-dea37afac9ad
github.com/codefly-dev/cli/contracts/deployment v0.0.0-20261006151622-5824cf5342fc
github.com/codefly-dev/core v0.19.17-0.20261029043538-2aa2e9aaf950
github.com/codefly-dev/interface-cache/go/cache v0.4.1
Expand Down
8 changes: 4 additions & 4 deletions module/services/accounts/code/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ github.com/codefly-dev/authority/libraries/authority-core/go v0.0.0-202610302220
github.com/codefly-dev/authority/libraries/authority-core/go v0.0.0-20261030222015-dea37afac9ad/go.mod h1:Cdk+10ebRh0tZA9ze2dDIrfQC34E+Y7LMi6UjSQ2dQU=
github.com/codefly-dev/authority/libraries/conformance/go v0.0.0-20261030222015-dea37afac9ad h1:DZt68NLXwaGYWXo1RUM0+JrvuXt/za/EyeHMGYFSix8=
github.com/codefly-dev/authority/libraries/conformance/go v0.0.0-20261030222015-dea37afac9ad/go.mod h1:or3dd9bqacXWMjke/n81l/QxRaLwq2lq/hL4V2qtAZo=
github.com/codefly-dev/authority/libraries/delivery/go v0.0.0-20261028224835-f82a98e093ef h1:Mso6TDL7zLY5HwR+gq0pRSNN/zO8fv89F9kzcPf+qI4=
github.com/codefly-dev/authority/libraries/delivery/go v0.0.0-20261028224835-f82a98e093ef/go.mod h1:XsOFnO2MQdr37vM3ULa0Uwi8ZWptyVx7hRSUyIdaZ1Q=
github.com/codefly-dev/authority/libraries/delivery/go v0.0.0-20261030222015-dea37afac9ad h1:gq8WatMLdoqsfwafxj2ihYSl0jIEw/d7ZMTGRWu9qpo=
github.com/codefly-dev/authority/libraries/delivery/go v0.0.0-20261030222015-dea37afac9ad/go.mod h1:XsOFnO2MQdr37vM3ULa0Uwi8ZWptyVx7hRSUyIdaZ1Q=
github.com/codefly-dev/authority/libraries/hop/go v0.0.0-20261027154629-b57068f61a0f h1:llYwKOBeCB6kS4faxICrR5YYlwnhiV+0qXjuT3IwBd4=
github.com/codefly-dev/authority/libraries/hop/go v0.0.0-20261027154629-b57068f61a0f/go.mod h1:/SZab4/ll1nAKTucP3h30rpcXo56BHmJWLkvs2ayaMs=
github.com/codefly-dev/authority/libraries/resources/go v0.0.0-20261028224835-f82a98e093ef h1:oJN5L6PkQB+VTVn1zsgXzSwiCO7eFUrd67PCkncrFI4=
github.com/codefly-dev/authority/libraries/resources/go v0.0.0-20261028224835-f82a98e093ef/go.mod h1:1rmjrVyr0h7zOuwOHS9i+BoeS9dr3XNvtupLZFwY6As=
github.com/codefly-dev/authority/libraries/resources/go v0.0.0-20261030222015-dea37afac9ad h1:ZuYv+9r6U08xLQ5c+AOSBzhkF7h3lqUj6kMa0S2OKKE=
github.com/codefly-dev/authority/libraries/resources/go v0.0.0-20261030222015-dea37afac9ad/go.mod h1:1rmjrVyr0h7zOuwOHS9i+BoeS9dr3XNvtupLZFwY6As=
github.com/codefly-dev/cli/contracts/deployment v0.0.0-20261006151622-5824cf5342fc h1:olDnVJ1A1Retn0z9A59YMwDRmDLgkV2y1lbl+HzNrj8=
github.com/codefly-dev/cli/contracts/deployment v0.0.0-20261006151622-5824cf5342fc/go.mod h1:VWPYY3FH4te7SzdN2xl9odNpWidJ1Grl/Hjs1SNoEF8=
github.com/codefly-dev/core v0.19.17-0.20261029043538-2aa2e9aaf950 h1:U5HeCDUfftwVFbMYN1HGPUL+9HO+ske3nkExu1C2kYY=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ func TestTheHopsRegisteredKeyIsPublishedApartFromTheWorkContextKeys(t *testing.T
require.Equal(t, id, published.ResourceID)
require.Equal(t, id, published.Payload["key_id"])
require.Equal(t, "authority/hop", published.Payload["workload"])
require.NotEmpty(t, published.Payload["instance"], "the hop instance the key is pinned to")
// The durable emitter writes the row and drops the whole payload when a
// key is not declared for the event, with a warning and nothing failing;
// the production check runs here so the declaration cannot drift.
require.NoError(t, business.ValidatePayload(published.EventType, published.Payload))

// A restart registers the same key again: one entry, renewed, and a
// renewal is not an event.
Expand Down
3 changes: 3 additions & 0 deletions module/services/accounts/code/pkg/business/audit_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,9 @@ var auditEventCatalog = []AuditEventDefinition{
mutation(EventHopAdmissionKeyPublished, CategorySecurity, "Keys began publishing a hop admission key, registered by the hop's attested workload.",
PayloadField{Name: "key_id", Kind: FieldString, Required: true},
PayloadField{Name: "workload", Kind: FieldString, Required: true},
// The hop instance (its pod) the key is pinned to; a credential naming
// no pod is refused before anything is published.
PayloadField{Name: "instance", Kind: FieldString, Required: true},
PayloadField{Name: "expires_at", Kind: FieldString, Required: true}),
mutation(EventModuleEnvelopeDelivered, CategorySecurity, "A release-signed revision of the module envelope was delivered.",
PayloadField{Name: "revision", Kind: FieldInt, Required: true},
Expand Down
15 changes: 14 additions & 1 deletion module/tools/cmd/module-package/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,22 @@ func main() {

func run(arguments []string) error {
if len(arguments) == 0 {
return fmt.Errorf("usage: module-package <validate|build|sign-provenance|run-generators|sync-embedded-fixtures|run-conformance|verify-release-policy|verify-release-ref|verify-release-ancestry>")
return fmt.Errorf("usage: module-package <validate|build|sign-provenance|run-generators|sync-embedded-fixtures|run-conformance|verify-host-interfaces|verify-release-policy|verify-release-ref|verify-release-ancestry>")
}
switch arguments[0] {
case "verify-host-interfaces":
flags := flag.NewFlagSet("verify-host-interfaces", flag.ContinueOnError)
moduleRoot := flags.String("module", ".", "module package root")
interfaces := flags.String("interfaces", "", "codefly-dev/authority's interfaces/ tree at the revision the services' go.mod pin")
revision := flags.String("revision", "", "the commit that tree was read at, held to the go.mod pin (optional)")
if err := flags.Parse(arguments[1:]); err != nil {
return err
}
return modulepackage.VerifyHostInterfaces(modulepackage.HostInterfaceOptions{
ModuleRoot: *moduleRoot,
InterfacesDir: *interfaces,
Revision: *revision,
}, os.Stdout)
case "validate":
flags := flag.NewFlagSet("validate", flag.ContinueOnError)
moduleRoot := flags.String("module", ".", "module package root")
Expand Down
2 changes: 1 addition & 1 deletion module/tools/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/Masterminds/semver/v3 v3.5.0
github.com/codefly-dev/core v0.19.7
github.com/yoheimuta/go-protoparser/v4 v4.14.2
golang.org/x/mod v0.41.0
golang.org/x/tools v0.50.0
google.golang.org/protobuf v1.36.12
gopkg.in/yaml.v3 v3.0.1
Expand Down Expand Up @@ -46,7 +47,6 @@ require (
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3 // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba // indirect
golang.org/x/mod v0.41.0 // indirect
golang.org/x/net v0.60.0 // indirect
golang.org/x/sync v0.23.0 // indirect
golang.org/x/sys v0.49.0 // indirect
Expand Down
Loading
Loading