test: gate releases on enforced conformance and installed package checks
Some checks failed
CI Smoke / host-smoke (push) Successful in 2s
CI Smoke / pytest-smoke (push) Failing after 5s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e747-8f27-7242-8df8-8bc44f88c929
This commit is contained in:
tegwick 2026-09-28 12:26:40 +02:00
parent a15fe032b0
commit 1ece969f59
6 changed files with 206 additions and 17 deletions

View file

@ -1,4 +1,4 @@
# CI smoke — package tests prove hub-core library health on push. # Local source, enforcement, inventory and installed-package gates.
name: CI Smoke name: CI Smoke
on: on:
@ -22,23 +22,21 @@ jobs:
pytest-smoke: pytest-smoke:
runs-on: self-hosted runs-on: self-hosted
steps: steps:
- name: Run hub-core pytest - name: Test enforcement, inventory and installed package
run: | run: |
set -eu set -eu
REF="${GITHUB_SHA:-main}" REF="${GITHUB_SHA:?commit SHA required}"
SHORT="${REF:0:7}" CI_WORKDIR="$(mktemp -d)"
ROOT="${HOME}/ci-hub-core-${SHORT}" trap 'rm -rf -- "$CI_WORKDIR"' EXIT
rm -rf "${ROOT}" wget -qO "$CI_WORKDIR/source.tar.gz" \
mkdir -p "${ROOT}" "https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${REF}.tar.gz"
wget -qO /tmp/hub-core.tar.gz \ mkdir "$CI_WORKDIR/source"
"https://forgejo.coulomb.social/${GITHUB_REPOSITORY}/archive/${SHORT}.tar.gz" tar xzf "$CI_WORKDIR/source.tar.gz" -C "$CI_WORKDIR/source" --strip-components=1
tar xzf /tmp/hub-core.tar.gz -C "${ROOT}" --strip-components=1 cd "$CI_WORKDIR/source"
cd "${ROOT}"
if ! command -v uv >/dev/null 2>&1; then if ! command -v uv >/dev/null 2>&1; then
pip install --user uv pip install --user uv
export PATH="${HOME}/.local/bin:${PATH}" export PATH="${HOME}/.local/bin:${PATH}"
fi fi
uv sync uv sync --locked --group dev --extra runtime
uv run python -c "import hub_core; print(hub_core.__version__)" make ci-check
uv run python -m pytest -q echo "hub-core source, enforcement, inventory and package checks passed @ ${REF}"
echo "hub-core pytest smoke ok @ ${SHORT}"

View file

@ -1,4 +1,4 @@
.PHONY: install test runtime-run conformance container-build ecosystem-regression .PHONY: install test runtime-run conformance container-build ecosystem-regression inventory-check package-check ci-check
UV ?= uv UV ?= uv
ECOSYSTEM_REGRESSION ?= /home/worsch/the-custodian/scripts/hub-ecosystem-regression.sh ECOSYSTEM_REGRESSION ?= /home/worsch/the-custodian/scripts/hub-ecosystem-regression.sh
@ -9,7 +9,7 @@ install:
$(UV) sync $(UV) sync
test: test:
$(UV) run python -m pytest -q $(UV) run --locked --extra runtime python -m pytest -q
runtime-run: runtime-run:
$(UV) run --extra runtime hub-core api $(UV) run --extra runtime hub-core api
@ -22,3 +22,13 @@ container-build:
ecosystem-regression: ecosystem-regression:
bash $(ECOSYSTEM_REGRESSION) bash $(ECOSYSTEM_REGRESSION)
# Local equivalents of the required CI gates.
inventory-check:
$(UV) run --locked --extra runtime python tools/build_access_inventory.py --inventory docs/platform-access-inventory.json --check
package-check:
$(UV) build --out-dir dist/ci
@set -eu; set -- dist/ci/*.whl; test "$$#" -eq 1; $(UV) run --no-project --with "$$1" python -I tools/check_installed_package.py
ci-check: test inventory-check package-check

View file

@ -46,3 +46,27 @@ absorption slices that are not part of the T04 minimal vertical. Tenant
isolation also remains open because the 0.1 runtime has no tenant identity or isolation also remains open because the 0.1 runtime has no tenant identity or
authorization context yet. These gaps must not be interpreted as passing; the authorization context yet. These gaps must not be interpreted as passing; the
harness reports only the implemented profile above. harness reports only the implemented profile above.
## Access enforcement and CI gates
`make ci-check` runs the test suite, checks the reviewed access inventory for
source drift, builds distributions and validates an installed wheel outside the
checkout's import path. Forgejo runs these gates for `main` pushes and manual
runs, using the full commit SHA and a unique temporary checkout. CI installs the
locked development and runtime dependencies first. Individual gates are
`make test`, `make inventory-check` and `make package-check`.
`tests/test_enforced_conformance.py` runs all twelve existing Tier 2/3 checks
through an explicitly enforced runtime using a real signed IAM JWT and synthetic
owner facts, policy and audit. It verifies event attribution against authorization
records. Additional journeys establish valid state, deny both reads and writes
for anonymous/invalid credentials, revoked entitlement, policy denial and
policy/audit outages, then independently read back unchanged stored messages.
These tests run in the ordinary suite; they need no external owner checkout.
The installed-wheel gate validates runtime/security imports, packaged action and
browser route coverage, contract fixtures/schemas and the migration template.
It makes no owner requests and starts no service. The separate optional Audit
Core interoperability suite still requires `HUB_CORE_AUDIT_CORE_SOURCE` and is
not silently represented as covered by ordinary CI. Local CI-equivalent success
is not a deployed Forgejo receipt or live owner/platform acceptance.

View file

@ -0,0 +1,89 @@
"""Disposable enforcement-mode journeys; synthetic owners, real signed IAM token.
These exercise the complete Tier 2/3 workload through AccessBoundary. They do
not establish issuer registration, deployed custody or platform acceptance.
"""
import asyncio
import json
import time
from dataclasses import replace
from uuid import uuid4
import pytest
from cryptography.hazmat.primitives.asymmetric import rsa
from fastapi.testclient import TestClient
from hub_core.conformance import ConformanceHarness
from hub_core.runtime.app import create_app
from hub_core.runtime.config import RuntimeSettings
from test_access_boundary import Owners
from test_access_identity import setup
@pytest.fixture(scope='module')
def signing_key():
return rsa.generate_private_key(public_exponent=65537, key_size=2048)
@pytest.fixture
def enforced(signing_key):
token, identity, _, upstream = setup(signing_key)
owners = Owners()
owners.facts = replace(owners.facts, producer_addresses=frozenset({'hub:ops-hub'}))
async def current_facts(actor, resource):
return replace(owners.facts, checked_at=time.time())
owners.resolve = current_facts
controller = owners.controller()
controller.identity = identity
app = create_app(settings=RuntimeSettings(environment='test', access_mode='enforce'),
access_controller=controller)
with TestClient(app, base_url='https://hub.example', headers={'Authorization': 'Bearer ' + token}) as client:
yield client, owners
asyncio.run(upstream.aclose())
def test_tier_2_and_3_workload_passes_through_enforcement(enforced):
client, owners = enforced
report = ConformanceHarness(client).run()
assert report.passed, report.to_dict()
assert report.passed_count == 12
assert owners.requests
assert all(r.actor.subject == 'immutable-root' for r in owners.requests)
records = {r['correlation_id']: r for r in owners.records if r['outcome'] == 'authorized'}
for family in ('progress', 'interaction'):
result = client.get('/ports/projections/' + family + '_events')
event = result.json()['data']['items'][0]
attribution = event['payload']['_hub_access']
record = records[attribution['correlation_id']]
assert record['subject'] == 'immutable-root'
assert 'Projection rebuild conformance fixture.' not in json.dumps(owners.records)
@pytest.mark.parametrize('failure,status', [('anonymous',401), ('invalid',401),
('revoked',403), ('policy_denied',403), ('policy_outage',503), ('audit_outage',503)])
def test_denied_reads_and_writes_leave_no_business_mutation(enforced, failure, status):
client, owners = enforced
assert ConformanceHarness(client).run().passed
before = client.get('/ports/projections/messages').json()['data']['items']
saved = client.headers['authorization']
if failure == 'anonymous':
del client.headers['authorization']
elif failure == 'invalid':
client.headers['authorization'] = 'Bearer invalid'
elif failure == 'revoked':
owners.facts = replace(owners.facts, root_entitled=False)
elif failure == 'policy_denied':
owners.allow = False
elif failure == 'policy_outage':
owners.policy_down = True
else:
owners.audit_down = True
message = {'schema_version':'0.1.0', 'correlation_id':str(uuid4()),
'from_address':'hub:ops-hub', 'to_addresses':['agent:conformance'],
'body':'must never commit'}
assert client.get('/ports/projections/messages').status_code == status
assert client.post('/ports/messaging/messages', json=message).status_code == status
client.headers['authorization'] = saved
owners.facts = replace(owners.facts, root_entitled=True)
owners.allow, owners.policy_down, owners.audit_down = True, False, False
assert client.get('/ports/projections/messages').json()['data']['items'] == before

View file

@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""Check an installed wheel outside the checkout's import path (use python -I).
Run via: uv run --no-project --with dist/<wheel> python -I tools/check_installed_package.py
No startup, owner requests, credentials or database connection are needed.
"""
import json
from importlib.resources import files
from pathlib import Path
import hub_core
from hub_core.conformance import ConformanceHarness
from hub_core.runtime.app import create_app
from hub_core.runtime.config import RuntimeSettings
from hub_core.runtime.inbox_projection import create_inbox_projection_router
from hub_core.security.boundary import iter_routes, route_key
from hub_core.security.browser import BROWSER_ROUTES, create_browser_router
def main():
checkout = Path(__file__).resolve().parents[1]
installed = Path(hub_core.__file__).resolve()
if installed.is_relative_to(checkout):
raise RuntimeError('package smoke imported checkout instead of installed wheel')
catalog = json.loads(files('hub_core.security').joinpath('routes.json').read_text())['routes']
app = create_app(settings=RuntimeSettings(environment='test', access_mode='enforce'))
routes = [*iter_routes(app), *iter_routes(create_inbox_projection_router())]
missing = [route_key(route, method) for route in routes if hasattr(route, 'methods')
for method in route.methods if route.path != '/healthz' and route_key(route, method) not in catalog]
if missing:
raise RuntimeError('installed action catalog is incomplete: ' + ', '.join(missing))
browser = {(method, route.path) for route in iter_routes(create_browser_router())
for method in route.methods}
if browser != BROWSER_ROUTES:
raise RuntimeError('installed browser route coverage differs')
# Constructor loads packaged contract fixtures; these checks load schemas.
harness = ConformanceHarness(None)
harness._schema_validate()
harness._no_secrets()
if not files('hub_core.migrations').joinpath('script.py.mako').is_file():
raise RuntimeError('installed migration template missing')
print('Installed wheel: imports, action catalog, browser routes, contract resources and migration template pass')
if __name__ == '__main__':
main()

View file

@ -325,6 +325,28 @@ T01–T04 remain `progress`; issuer registration/MFA, owner-facts composition,
MCP consumer adoption, operation-outcome auditing and platform conformance remain MCP consumer adoption, operation-outcome auditing and platform conformance remain
open. No production listener or entitlement changed. open. No production listener or entitlement changed.
## Conformance and CI continuation — 2026-09-28
Added enforcement-mode Tier 2/3 conformance journeys with signed IAM tokens and
explicit synthetic owners. Denial/revocation/outage cases exercise reads and
writes and verify unchanged business state after restoring access. Event
attribution is joined to recorded authorization decisions.
Forgejo now runs `make ci-check`: the complete ordinary test suite, access
inventory drift checks, distribution builds and an isolated installed-wheel
resource/import check. CI checks out the full commit into a unique temporary
directory and installs locked development/runtime dependencies. The optional
owner-source interoperability suite remains separately identified.
See [conformance documentation](../docs/conformance.md#access-enforcement-and-ci-gates).
Validation: local `make ci-check` passed with **330 tests**, one explicitly
optional owner-source module skipped, inventory coverage (165 Hub surfaces),
distribution builds and installed-wheel checks. Final locked runtime dependency
sync and workflow YAML/shell syntax checks also pass.
These are local source/release gates, not live platform or remote CI acceptance;
T01–T04 remain `progress` and T06 remains open.
## Acceptance checkpoints ## Acceptance checkpoints
- [x] Architecture/source/runtime review captured; new implementation owner is hub-core - [x] Architecture/source/runtime review captured; new implementation owner is hub-core