All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 50s
TEN-WP-0008. railiance/app.toml declares criticality=high, empty secrets, isolated canary, and the live PostgreSQL digest as previous_stable. Manifests render through kustomize (deploy/ and deploy/canary/). Stage 1 passed. Stage 2/3 Helm-only CLI gap requested as RAIL-BS-IN-0001 rather than a dummy chart. Assistant: grok Assistant-Session: 01a04cea-e5e8-7081-a0fc-808ebbc35fa9
134 lines
6.9 KiB
Markdown
134 lines
6.9 KiB
Markdown
# SCOPE
|
|
|
|
> Lightweight boundary for agents and contributors. Full contract:
|
|
> `net-kingdom/canon/standards/tenant-engine-boundary-contract_v0.1.md`.
|
|
> Aspirational role: `INTENT.md`. Layer declaration: Engine / PIP
|
|
> (`INTENT.md` frontmatter; `TEN-DEC-2026-001`).
|
|
|
|
---
|
|
|
|
## One-liner
|
|
|
|
Canonical PIP of tenant-as-an-entity facts for NetKingdom: existence,
|
|
lifecycle, onboarding grouping, capability roles, plan/subscription
|
|
assignment, and guardrail ceilings.
|
|
|
|
---
|
|
|
|
## Core Idea
|
|
|
|
`tenant-engine` answers "what is this tenant, what roles does it hold, what
|
|
plan is it on, and how far may it go" for two consumers: `key-cape`
|
|
(cached, at token issuance) and `access-engine` / `flex-auth` (live, for
|
|
high-stakes decisions). It never stores users, issues tokens, evaluates
|
|
approvals, or makes authorization decisions. Tenancy context is an input to
|
|
the decision, not a decision.
|
|
|
|
---
|
|
|
|
## Layer
|
|
|
|
| Key | Value |
|
|
| --- | --- |
|
|
| Layer | **Engine** |
|
|
| Role | **PIP** |
|
|
| Statute | `net-kingdom/canon/standards/security-layer-model_v0.7.md` |
|
|
| Companion | `net-kingdom/SECURITY-COMPANION.md` |
|
|
| Catalog row | tenant-as-an-entity facts (`§4`) |
|
|
| Tooling contacts | none (`key-cape` and OpenBao are not clients of this repo) |
|
|
| Non-Tooling clients | PostgreSQL / SQLite (own store); `flex-auth` `POST /v1/check` (Engine API on the write and authorized-read path); State Hub (work records, not a runtime dependency) |
|
|
| Write path | PEP-shaped: fail-closed when `access-engine` is unset or unreachable |
|
|
| Conformance today | Declaration is in our own voice. Mechanical `layer.yaml` check, persisted decision records, published stance map, and independent evidence custody are **not** yet shipped — see the review and `TEN-WP-0011`. |
|
|
|
|
---
|
|
|
|
## In Scope
|
|
|
|
- Tenant records: identifier, lifecycle (`active` / `retired`), current
|
|
onboarding grouping (ADR-0013). Grouping is mutable through an audited
|
|
reclassification, not by renaming `tenant_id`.
|
|
- Capability role grants/revocations: `PLTF`/`IAM`/`VEN`/`CUS` (ADR-0014),
|
|
audited, mostly plan-linked.
|
|
- Plan/subscription assignment, referenced by `adaptive-pricing` plan id.
|
|
- Guardrail/quota *policy*: spend / entity-count / action-count ceilings,
|
|
resolved as a total function of grouping, plan, override, and lifecycle.
|
|
Seeded key: `spend.monthly`. `trial` defaults to zero.
|
|
- Cache-read API for `key-cape` (token-issuance-time `tenant_roles` claim
|
|
source): `GET /tenants/{id}/roles`.
|
|
- Live-lookup API for `access-engine` (high-stakes, `aal2`-class
|
|
decisions): `GET /tenants/{id}/roles/live`. Store unavailability returns
|
|
`503`, never `200` plus empty roles.
|
|
- Write API for create / grant / revoke / plan / metadata / retire /
|
|
reactivate / grouping / guardrail mutations, authorization-gated by
|
|
`flex-auth`. Unset or unreachable authorizer denies.
|
|
- Authoritative tenant read with ETag / If-Match / idempotency on
|
|
lifecycle and guardrail mutations.
|
|
|
|
## Out of Scope
|
|
|
|
- Identity, authentication, MFA, token issuance — `key-cape`/Keycloak.
|
|
- Authorization decisions — `access-engine` is the PDP; `tenant-engine` is
|
|
a data source it queries, never the other way around.
|
|
- Approval objects and approval lifecycle — `approval-engine`. Contested
|
|
in `TEN-DEC-2026-001`; this repo will not grow one.
|
|
- Users, profiles, memberships — `user-engine`. `tenant_id` is the only key
|
|
shared between the two services.
|
|
- Pricing-model / plan term definitions — `adaptive-pricing`.
|
|
- Payment processing — not yet identified as owned by any repo.
|
|
- Runtime secret custody — OpenBao / `secrets-engine`.
|
|
- Metering / consumption counters — whoever meters the resource writes
|
|
them; this service does not observe spend.
|
|
- Rate limiting / traffic shaping — gateway concern, not `action_count`.
|
|
- Containment / actuation — unowned and held at zero estate-wide.
|
|
- Irreversible operational decisions without human approval.
|
|
- Direct Tooling-layer clients — Staff and agents reach tenant facts
|
|
through this Engine, not past it.
|
|
|
|
## Current State
|
|
|
|
Production service, not a bootstrap. Finished workplans `TEN-WP-0001`
|
|
through `TEN-WP-0007`, `TEN-WP-0009`, and `TEN-WP-0010` shipped the domain
|
|
model, the three boundary-contract APIs, the `flex-auth` write authorizer,
|
|
lifecycle, guardrails, PostgreSQL as the production store, and mutable
|
|
grouping. `TEN-WP-0008` (staged-promotion onboarding) is still `ready`,
|
|
not done.
|
|
|
|
| Surface | Shipped | Notes |
|
|
| --- | --- | --- |
|
|
| Domain model + SQLite/in-memory store | yes | `TEN-WP-0002` |
|
|
| Cache-read / live-lookup / write APIs | yes | `TEN-WP-0002` |
|
|
| `flex-auth` `WriteAuthorizer` | yes | Fail-closed; `is_allowed()` returns a bool and **discards the decision envelope** |
|
|
| Production runtime | yes | `TEN-WP-0004`; image pin in `deploy/base/tenant-engine.yaml` |
|
|
| Lifecycle (update / retire / reactivate) | yes | `TEN-WP-0005`; no hard-delete |
|
|
| Guardrail policy | yes | `TEN-WP-0006` / `0007`; `docs/tenant-guardrail-policy.md` |
|
|
| PostgreSQL production store | yes | `TEN-WP-0009`; deploy mounts `TENANT_ENGINE_DATABASE_URL_FILE` |
|
|
| Mutable grouping | yes | `TEN-WP-0010`; identifier segment stays historical |
|
|
| Staged promotion | yes (declared) | `TEN-WP-0008`; `railiance/app.toml`; live pin recorded as `previous_stable`. Helm CLI apply is a railiance-bootstrap gap (`RAIL-BS-IN-0001`). |
|
|
| Machine-readable `layer.yaml` | yes | `TEN-WP-0011-T01`; check in `scripts/check_layer_conformance.py` |
|
|
| Persisted `authorization_decision_id` | yes | `authz_records` plus mutation event payload (`TEN-WP-0011-T02`) |
|
|
| Published unreachable-engine stance map | yes | `pep-stance.yaml`, fail-closed, tested equal to shipped behaviour |
|
|
| Independent audit-core emission | path shipped, sender pending | Local outbox + POST `/v1/events`; `AUDIT-IN-0002` |
|
|
| Bounded event-read interface | yes | `events_for(tenant_id)` only (`TEN-WP-0011-T05`) |
|
|
| Claim freshness / input-class lifetime | yes | `pip-claims.yaml` (`TEN-WP-0011-T03`) |
|
|
|
|
The boundary contract still labels guardrail policy "reserved, not
|
|
implemented" and still calls this repo "not a policy enforcement point".
|
|
Both sentences are stale: guardrails shipped, and the write path is
|
|
PEP-shaped even though this repo is not a PDP. Amendment is a
|
|
`net-kingdom` change, requested from `TEN-WP-0011`.
|
|
|
|
## Getting Oriented
|
|
|
|
- Start with: `INTENT.md`
|
|
- Working companion: `net-kingdom/SECURITY-COMPANION.md`
|
|
- Statute: `net-kingdom/canon/standards/security-layer-model_v0.7.md`
|
|
- Ownership contract: `net-kingdom/canon/standards/tenant-engine-boundary-contract_v0.1.md`
|
|
- Claim/carrying mechanism: `net-kingdom/canon/standards/iam-profile_v0.3.md`
|
|
- Layer declaration: `decisions/decisions.md` `TEN-DEC-2026-001`
|
|
- Review: `history/2026-08-29-security-layer-intent-scope-review.md`
|
|
- Evolution workplan: `workplans/TEN-WP-0011-security-layer-conformance.md`
|
|
- flex-auth write-authorization integration: `docs/flex-auth-integration.md`
|
|
- Guardrail contract: `docs/tenant-guardrail-policy.md`
|
|
- Lifecycle contract: `docs/tenant-lifecycle-api.md`
|
|
- Agent instructions: `AGENTS.md`, `CLAUDE.md`
|
|
- Workplans: `workplans/`
|