Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e85804b
feat(registry-server): add configurable registry runtime
jeremi Aug 30, 2026
b26275a
feat(server): add governed semantic metadata projection
jeremi Aug 30, 2026
9071486
docs(registry-server): focus event hook direction
jeremi Aug 30, 2026
a1f455b
feat(registry-server): add governed event webhooks
jeremi Aug 30, 2026
531c6eb
feat(server): add governed query and derived fields
jeremi Aug 30, 2026
6a20add
fix(server): close registry query gaps
jeremi Aug 30, 2026
681656d
fix(server): enforce derived relation cardinality
jeremi Aug 30, 2026
8281286
fix(server): canonicalize derived relation keys
jeremi Aug 30, 2026
fb8b63e
Merge governed query and event webhook implementations
jeremi Aug 30, 2026
0c18af6
Merge latest registry query fixes
jeremi Aug 30, 2026
cd90e37
fix(registry-server): align governed API and webhook workflows
jeremi Aug 30, 2026
0e0afaf
feat(registry-server): streamline adopter experience
jeremi Aug 30, 2026
85af495
fix(ci): configure registry server test environment
jeremi Aug 30, 2026
38445ef
fix(registry-server): close schema identifier catalog
jeremi Aug 30, 2026
268c783
fix(registry-server): close repository gates
jeremi Aug 30, 2026
13d0db7
test(registry-server): align mutation discovery contract
jeremi Aug 30, 2026
9f38af0
fix(registry-server): validate correlated fixture problems
jeremi Aug 30, 2026
8dc81d5
test(registry-server): stabilize request log capture
jeremi Aug 30, 2026
d6b5e13
test(registry-server): bind captured request log
jeremi Aug 30, 2026
6a53a96
test(registry-server): repair adopter lifecycle
jeremi Aug 30, 2026
f806b22
ci(registry-server): provision quickstart tooling
jeremi Aug 30, 2026
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
5 changes: 5 additions & 0 deletions .github/scripts/ci_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"registry-relay-client-py",
),
"relay-v2": ("registry-relay-v2", "registry-relayctl"),
"registry-server": ("registry-server", "registry-serverctl"),
"evidence": (
"registry-evidence",
"registry-evidence-authoring",
Expand All @@ -68,6 +69,7 @@
MANIFEST_PACKAGES = frozenset(SHARDS["manifest"])
RELAY_V2_PACKAGES = frozenset(SHARDS["relay-v2"])
RELAY_CLIENT_PACKAGES = frozenset(SHARDS["relay-client"])
REGISTRY_SERVER_PACKAGES = frozenset(SHARDS["registry-server"])

# Provider publication is part of the Discovery product contract even though
# Evidence and Relay own its generation and serving code. Keep this explicit:
Expand Down Expand Up @@ -514,6 +516,8 @@ def classify(
seeds.update(PLATFORM_PACKAGES)
elif path.startswith("products/relay-v2/"):
seeds.update(RELAY_V2_PACKAGES)
elif path.startswith("products/registry-server/"):
seeds.update(REGISTRY_SERVER_PACKAGES)
elif path.startswith("products/identifiers/"):
# The catalog gate compiles its focused Relay V2 exporter.
# Catalog-only tooling does not require the full Rust matrix.
Expand Down Expand Up @@ -706,6 +710,7 @@ def classify(
or any(path in DISCOVERY_TUTORIAL_INPUTS for path in paths),
"relay_v2_contracts": bool(affected & RELAY_V2_PACKAGES),
"relay_client_contracts": bool(affected & RELAY_CLIENT_PACKAGES),
"registry_server_contracts": bool(affected & REGISTRY_SERVER_PACKAGES),
"evidence_contracts": bool(affected & EVIDENCE_PACKAGES),
"release_tool": release_tool,
"release_source_proof": release_source_proof,
Expand Down
101 changes: 101 additions & 0 deletions .github/scripts/test_ci_changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
EVIDENCE_AUTHORING_GUIDE_IMPLEMENTATION_INPUTS,
EVIDENCE_TUTORIAL_INPUTS,
IDENTIFIER_CATALOG_INPUTS,
REGISTRY_SERVER_PACKAGES,
SECURITY_WORKFLOW_GATES,
SHARDS,
Workspace,
Expand Down Expand Up @@ -371,6 +372,38 @@ def test_relay_v2_product_material_selects_runtime_and_tooling(self) -> None:
self.assertTrue(outputs["relay_v2_contracts"])
self.assertTrue(outputs["editors"])

def test_registry_server_paths_select_its_shard_and_product_gate(self) -> None:
for path in (
"crates/registry-server/src/compiler.rs",
"crates/registry-serverctl/src/main.rs",
"products/registry-server/contracts/definition-of-done.yaml",
):
with self.subTest(path=path):
outputs = classify(self.workspace, (path,))
self.assertTrue(outputs["registry_server_contracts"])
self.assertTrue(
set(outputs["rust_packages"]) & REGISTRY_SERVER_PACKAGES
)

product_outputs = classify(
self.workspace,
("products/registry-server/contracts/definition-of-done.yaml",),
)
self.assertEqual(
set(REGISTRY_SERVER_PACKAGES),
set(product_outputs["rust_packages"]) & REGISTRY_SERVER_PACKAGES,
)

def test_manifest_core_changes_select_registry_server_through_linked_code(
self,
) -> None:
manifest_change = ("crates/registry-manifest-core/src/lib.rs",)
outputs = classify(self.workspace, manifest_change)

self.assertTrue(outputs["registry_server_contracts"])
self.assertIn("registry-server", outputs["rust_packages"])
self.assertIn("registry-manifest-core", outputs["rust_packages"])

def test_evidence_tutorial_inputs_cover_every_registered_tutorial(self) -> None:
# The gate's registry is the source of truth for which tutorials exist.
# A tutorial missing here would not trigger the job that replays it, so
Expand Down Expand Up @@ -842,15 +875,83 @@ def test_current_contract_gates_replace_the_retired_notary_gate(self) -> None:
self.assertNotIn("\n notary-contracts:\n", workflow)
self.assertNotIn("notary_contracts", workflow)

self.assertIn("\n registry-server-contracts:\n", workflow)
self.assertIn("name: Registry Server product contracts", workflow)
self.assertIn(
"products/registry-server/scripts/check-contracts.sh", workflow
)
self.assertIn(
"products/registry-server/scripts/test-postgres.sh", workflow
)
self.assertIn(
"products/registry-server/scripts/test-adopter-workflow.sh", workflow
)

rust_result = workflow.split("\n rust-result:\n", 1)[1].split(
"\n release-tool:\n", 1
)[0]
self.assertIn("\n - discovery-contracts\n", rust_result)
self.assertIn("\n - evidence-contracts\n", rust_result)
self.assertIn("\n - relay-v2-contracts\n", rust_result)
self.assertIn("\n - relay-client-contracts\n", rust_result)
self.assertIn("\n - registry-server-contracts\n", rust_result)
self.assertNotIn("\n - notary-contracts\n", rust_result)

def test_registry_server_contracts_pin_postgresql_and_use_the_product_entry_points(
self,
) -> None:
workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8")
registry_server_job = workflow.split(
"\n registry-server-contracts:\n", 1
)[1].split("\n identifiers:\n", 1)[0]

self.assertIn(
"postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675",
registry_server_job,
)
self.assertIn(
"ports:\n - 5432/tcp",
registry_server_job,
)
self.assertIn(
"DATABASE_PORT: ${{ job.services.postgres.ports['5432'] }}",
registry_server_job,
)
self.assertIn(
"REGISTRY_SERVER_TEST_DATABASE_URL=postgresql://registry_server:registry_server_test@localhost:${DATABASE_PORT}/registry_server",
registry_server_job,
)
self.assertIn(
"REGISTRY_SERVER_TEST_TLS_DATABASE_URL=postgresql://registry_server:registry_server_test@localhost:${DATABASE_PORT}/registry_server",
registry_server_job,
)
self.assertIn(
"REGISTRY_SERVER_TEST_TLS_HOSTNAME_MISMATCH_DATABASE_URL=postgresql://registry_server:registry_server_test@127.0.0.1:${DATABASE_PORT}/registry_server",
registry_server_job,
)
self.assertIn(
"POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }}",
registry_server_job,
)
self.assertIn(
"TLS_CA_PEM_PATH: ${{ runner.temp }}/registry-server-postgres-trusted-ca.pem",
registry_server_job,
)
self.assertIn(
"uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d",
registry_server_job,
)
self.assertIn('version: "0.11.16"', registry_server_job)
for entry_point in (
"products/registry-server/scripts/check-contracts.sh",
"products/registry-server/scripts/test-postgres.sh",
"products/registry-server/scripts/test-postgres-tls.sh",
"products/registry-server/scripts/test-adopter-workflow.sh",
"products/registry-server/quickstart/run.sh --smoke",
):
with self.subTest(entry_point=entry_point):
self.assertIn(entry_point, registry_server_job)

def test_discovery_contracts_pins_node_for_adopter_binding_tests(self) -> None:
workflow = Path(".github/workflows/ci.yml").read_text(encoding="utf-8")
discovery_job = workflow.split("\n discovery-contracts:\n", 1)[1].split(
Expand Down
72 changes: 72 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
discovery_contracts: ${{ steps.filter.outputs.discovery_contracts }}
relay_v2_contracts: ${{ steps.filter.outputs.relay_v2_contracts }}
relay_client_contracts: ${{ steps.filter.outputs.relay_client_contracts }}
registry_server_contracts: ${{ steps.filter.outputs.registry_server_contracts }}
evidence_contracts: ${{ steps.filter.outputs.evidence_contracts }}
release_tool: ${{ steps.filter.outputs.release_tool }}
release_source_proof: ${{ steps.filter.outputs.release_source_proof }}
Expand Down Expand Up @@ -592,6 +593,76 @@ jobs:
- name: Relay client source neutrality
run: products/relay-v2/scripts/check-source-neutrality.sh

registry-server-contracts:
name: Registry Server product contracts
needs: changes
if: needs.changes.outputs.registry_server_contracts == 'true'
runs-on: ubuntu-24.04
timeout-minutes: 20
services:
postgres:
# Docker Hub PostgreSQL 17.11 index, verified 2026-08-29.
image: postgres:17.11@sha256:67f41722b7a8cbdb868a44a4995c846eddfdc2973bccb291ce937dce88ad5675
env:
POSTGRES_DB: registry_server
POSTGRES_PASSWORD: registry_server_test
POSTGRES_USER: registry_server
options: >-
--health-cmd "pg_isready -U registry_server -d registry_server"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432/tcp
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
submodules: false

- name: Configure Registry Server test environment
env:
DATABASE_PORT: ${{ job.services.postgres.ports['5432'] }}
POSTGRES_CONTAINER_ID: ${{ job.services.postgres.id }}
TLS_CA_PEM_PATH: ${{ runner.temp }}/registry-server-postgres-trusted-ca.pem
run: |
{
echo "REGISTRY_SERVER_TEST_DATABASE_URL=postgresql://registry_server:registry_server_test@localhost:${DATABASE_PORT}/registry_server"
echo "REGISTRY_SERVER_TEST_TLS_DATABASE_HOST=localhost"
echo "REGISTRY_SERVER_TEST_TLS_DATABASE_URL=postgresql://registry_server:registry_server_test@localhost:${DATABASE_PORT}/registry_server"
echo "REGISTRY_SERVER_TEST_TLS_HOSTNAME_MISMATCH_DATABASE_URL=postgresql://registry_server:registry_server_test@127.0.0.1:${DATABASE_PORT}/registry_server"
echo "REGISTRY_SERVER_TEST_TLS_POSTGRES_CONTAINER_ID=${POSTGRES_CONTAINER_ID}"
echo "REGISTRY_SERVER_TEST_TLS_CA_PEM_PATH=${TLS_CA_PEM_PATH}"
} >> "${GITHUB_ENV}"

- name: Cache Cargo registry
uses: Swatinem/rust-cache@f0d9c3887740aee45f6153b24b3a6b815192ec16 # v2
with:
shared-key: workspace-registry
cache-targets: false
save-if: ${{ github.ref == 'refs/heads/main' }}

- name: Install uv
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
version: "0.11.16"

- name: Registry Server contract consistency
run: products/registry-server/scripts/check-contracts.sh

- name: Registry Server PostgreSQL journeys
run: products/registry-server/scripts/test-postgres.sh

- name: Registry Server PostgreSQL TLS proof
run: products/registry-server/scripts/test-postgres-tls.sh

- name: Registry Server clean-checkout adopter workflow
run: products/registry-server/scripts/test-adopter-workflow.sh

- name: Registry Server generic quickstart
run: products/registry-server/quickstart/run.sh --smoke

identifiers:
name: Public identifier catalog
needs: changes
Expand Down Expand Up @@ -627,6 +698,7 @@ jobs:
- evidence-contracts
- relay-v2-contracts
- relay-client-contracts
- registry-server-contracts
- identifiers
runs-on: ubuntu-24.04
env:
Expand Down
Loading