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
116 changes: 115 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ runtime, records and the org-directory page.
is refused by name (this week's `modelservice` typo); a check refuses another
audience and a tampered token; an uninstall refuses an outstanding token on the
next check; an installation acts for itself within its role; a pending
installation is issued nothing; a workload is issued its binding's headless
installation is issued no ordinary capability; a workload is issued its binding's headless
scopes and refused an undeclared binding, a binding addressed elsewhere, a
widened scope, a forged credential; a child hop attenuates and names its actor;
`Keys` lets an independent core verifier check what was issued; TTL clamps.
Expand Down Expand Up @@ -1246,3 +1246,117 @@ The edge serves it to the browser on the Setup tab's Connect face. The shared
suite proves it in `RunSolutionPrincipalTarget` (`held_installations.go`). The
edge accepts installation `<0.5.0`; a host must serve `ListHeld` and pass that
case before a consumer relies on it.

### Pending installation setup delivery

The shared Go owner exposes `IssueInstallationStep(ctx, InstallationStepAttempt,
remainingLease)` for a **trusted host queue claimant**, and
`VerifyInstallationStep(ctx, token, audience)` for setup admission. This does not
change ordinary pending-installation refusal. The attempt pins the canonical
installation ID, organization, target name, revision and consent receipt, plus
the original reviewed delivery's principal (`TargetID`), generation and digest.
A host release-table target UUID is a different identity and remains part of the
host's immutable target/release/binding check. The claimant persists that original
association and receipt, never a token, and checks its job lease before minting.

The credential uses Core's existing signer/verifier and a private pending-only
seal source. Its only scope is `installations:install` on that installation ID.
An opaque operation binding covers the exact attempt. No agent-role data scopes
or person/team grants are added. Normal `Verify`, `Check`, child exchange and
issuance cannot consume it, including after activation at the same revision.
Expiry is at most one minute, the configured maximum, and the supplied remaining
lease. The verifier adds no clock-skew extension to this window. Delivery is
idempotent while the attempt remains pending; the host still owns live queue
lease validation, retry and completion fencing. A lease cancellation is not
represented as an Authority revocation and must not be claimed as one.

The existing `Check` transport reaches this verifier only with the exact method
`POST /_codefly/installations` or
`/host.installation.v1.InstallableService/Install`. These reserved setup methods
do not admit an ordinary capability, and advisory mode cannot relax their
credential checks. Receiver code supplies its own delivered audience and actual
method. Before invoking a configured callback or returning a cached ACK, it
compares the verified organization, installation ID and revision against strict
JSON `{installation_id, organization_id, revision}` and both installation
headers. An absent callback refuses; a solution may explicitly provide a no-op.
The owner library alone does not supply that runtime receiver or the host job
adapter; both require integration qualification.

This is a method-policy compatibility change without a protobuf field or RPC
change: an older setup sender's ordinary agent capability is not accepted at
either reserved method. Hosts must adopt the dedicated pending-step issuer and
receivers must enforce the setup check before enabling canonical installation
delivery. There is no fallback to an ordinary token, delivered method policy,
or advisory acceptance when either side has not adopted the setup contract.

`InstallStep` enqueues idempotently and returns failure/pending until that exact
job acknowledges. Enqueue success is never setup success. Only `Install`'s final
authorization, consent, generation and revision transaction activates canonical
state; no queue trigger activates it or a public installation mirror. Revocation,
replacement approval, redelivery and activation invalidate outstanding setup
credentials. The final state read is admission, not an atomic reservation through
callback I/O; a racing state change still prevents final installation activation.
Module installations and existing fixture-only trusted setup remain unchanged.


### Declared installation authority

The signed authority document and shared Go delivery/offer types carry
`InstallationRole` and `EdgeDependencies{Module, Presence}`. Core's module parser
validates the declarations; subsequent carriers preserve the exact strings and
list order without trimming, defaults or inferred module identities. Edge
presence (`required` or `optional`) grants nothing. Each `Module` is the exact
signed `domain.Module.Principal`. The host resolves it and binding audiences
through the existing catalogue to live target UUIDs and bindings, then reviews
and fences those delivered prerequisites. A principal is never assumed to be a
target UUID; route aliases, binding IDs and release strings are not fallbacks.
This list is not effective access or a substitute for per-module consent.
Nil and empty dependency lists mean the same declaration. Absent fields are
omitted from `domain.Module` JSON, preserving the old review digest. Changes to
nonempty fields change the consent digest and require a fresh review.

`Install` uses the declaration as follows: an absent selector retains explicit
caller selection; a named selector selects that declared role, accepting an empty
request or the same role; literal `none` accepts only an empty role request and
creates no standing authority. A caller may never submit `none` as a role. A
conflicting caller role refuses. Canonical `Installation.AgentRole` retains
`none` as a no-standing-authority marker, not a role or grant row. The installation
still has its stable principal and can use pending-only setup delivery. Ordinary
installation issuance refuses, and neither installer nor any person/team receives
an automatic grant. Existing installer-role and nonempty-role rules are unchanged.

Hosts persist the original request separately from the effective machine role:
retry the original empty role request, never the stored `none` marker. Consent
intent, pending retry, revocation and final acknowledgement fences still apply.
This does not implement active installation re-consent or migrate existing active
installations to a new role selector.

The new fields and reserved setup-method comments are exported through maintained
Codefly generation into local bindings, contracts and Go/Python/TypeScript clients.
The local document and offer adapters carry them. Tests exercise real signatures
on both generated delivery messages, the authenticated reader and persistence,
including disagreement refusal before storage. CLI producer construction and
Accounts queue/receiver integration still require their own qualification; these
local tests do not establish a deployed installation.


The two signed delivery carriers must agree on these declarations. Shared
`delivered.Pair` and `delivered.Module` refuse a different selector or a different
ordered `(Module, Presence)` dependency list; neither carrier takes precedence.
Empty and `none` differ, while nil and empty edge lists compare equally. A new
nonempty declaration present on only one carrier refuses, including an absent
sidecar. Legacy delivery with both declarations absent remains supported.
This compares two projections of one authored value; it adds no declaration
parser, sorting, trimming or defaulting. `FromCore` alone is a projection, not
paired-delivery admission. Hosts use the shared paired reader before persistence.
The CLI must fill both generated carriers from the same resolved declaration,
and each host must adopt its wire adapters before complete delivery is enabled.

The generation baseline used released Codefly 0.1.221 and proto companion 0.0.18:
unchanged pre-feature proto inputs reproduced their tracked outputs exactly.
Repeated generation of the new proto and all three clients is byte-identical,
and `codefly generate contracts authority --check` passes. Client generation
selects `--module-name api` explicitly to preserve the existing root Go package
when consuming the exported contracts directory. Only existing reviewed entries
in the generated-file inventory have their hashes refreshed; no exclusion is
added. SQL/cell installation evidence remains owned by the integrating host.
70 changes: 67 additions & 3 deletions libraries/authority-client/contract/catalog.codefly.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,87 @@
{
"schema": "codefly/module-api-contracts/v1",
"package": "local",
"package": "codefly/authority",
"version": "0.1.0",
"endpoints": [
{
"service": "local",
"endpoint": "grpc",
"api": "grpc",
"kind": "protobuf",
"package": "api",
"package": "",
"path": "contract.binpb",
"digest": "sha256:2d74a1ad05ecab544606e2e52630cc5cb6c16729371f091262dfb45a686d2712",
"digest": "sha256:b49a5399e647c61b1991fc22bf7fcf8262ab17333dbe01b4afd1d16c346f3ea7",
"services": [
{
"name": "LocalService",
"fullName": "api.LocalService",
"procedures": [
"/api.LocalService/Version"
]
},
{
"name": "ArtifactService",
"fullName": "host.artifact.v1.ArtifactService",
"procedures": [
"/host.artifact.v1.ArtifactService/Approve",
"/host.artifact.v1.ArtifactService/Authorize",
"/host.artifact.v1.ArtifactService/Revoke"
]
},
{
"name": "AuthorityService",
"fullName": "host.authority.v1.AuthorityService",
"procedures": [
"/host.authority.v1.AuthorityService/AttachResource",
"/host.authority.v1.AuthorityService/AuthorizeTransfer",
"/host.authority.v1.AuthorityService/Check",
"/host.authority.v1.AuthorityService/Delegate",
"/host.authority.v1.AuthorityService/DetachResource",
"/host.authority.v1.AuthorityService/GetDelegation",
"/host.authority.v1.AuthorityService/Issue",
"/host.authority.v1.AuthorityService/Keys",
"/host.authority.v1.AuthorityService/ListResources",
"/host.authority.v1.AuthorityService/RegisterAdmissionKey",
"/host.authority.v1.AuthorityService/RevokeDelegation"
]
},
{
"name": "CompositionService",
"fullName": "host.composition.v1.CompositionService",
"procedures": [
"/host.composition.v1.CompositionService/ApplyManifest"
]
},
{
"name": "InstallationService",
"fullName": "host.installation.v1.InstallationService",
"procedures": [
"/host.installation.v1.InstallationService/Current",
"/host.installation.v1.InstallationService/GrantRole",
"/host.installation.v1.InstallationService/Install",
"/host.installation.v1.InstallationService/List",
"/host.installation.v1.InstallationService/ListHeld",
"/host.installation.v1.InstallationService/ListRoleGrants",
"/host.installation.v1.InstallationService/Review",
"/host.installation.v1.InstallationService/RevokeRole"
]
},
{
"name": "OfferService",
"fullName": "host.installation.v1.OfferService",
"procedures": [
"/host.installation.v1.OfferService/ListOffers",
"/host.installation.v1.OfferService/ReviewOffer"
]
},
{
"name": "SessionService",
"fullName": "host.session.v1.SessionService",
"procedures": [
"/host.session.v1.SessionService/Current",
"/host.session.v1.SessionService/ListFixturePeople",
"/host.session.v1.SessionService/SignIn"
]
}
]
}
Expand Down
Binary file modified libraries/authority-client/contract/contract.binpb
Binary file not shown.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading