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
2 changes: 1 addition & 1 deletion docs/OPERATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

Docker Verify builds each service locally (`load: true`, no push) and runs pinned Trivy v0.74.0 against that local image. Docker Publish pushes digest-only candidates: it does not assign normal `sha-*` or `v*` release tags while individual service gates are running.

Each service must pass HIGH/CRITICAL Trivy scanning, then be signed and receive SPDX/SLSA attestations for the same candidate digest. The `promote` job runs only after all nine matrix builds succeed; it validates all nine reports, source commit, digest subjects, signer identity, and verified DSSE predicates before inspecting or writing any tags.
Each service must pass HIGH/CRITICAL Trivy scanning, then be signed and receive SPDX/SLSA attestations for the same candidate digest. The `promote` job runs only after all nine matrix builds succeed; it validates all nine reports, source commit, digest subjects, signer identity, and verified DSSE predicates before inspecting or writing any tags. A changed backend image requires a new service release version in both `services/pom.xml` and its owner POM; an existing version tag may only be reused for the identical digest. Keep contract fixtures aligned with the intended release versions instead of weakening the immutable-tag guard.

Use `release-manifest` artifact from successful Docker Publish run as canonical deployment input. It contains complete nine-service `release-manifest.txt`, `release-set.json`, and per-service evidence. Local `scripts/runbooks/promote-release.sh EVIDENCE_DIR SOURCE_SHA ghcr.io/davidhlp/ulticode` supports read-only dry-run only; `--execute` is restricted to Docker Publish on `main`. The workflow uses repository-wide `ulticode-release-tag-writer` concurrency with cancellation disabled. If promotion fails after candidate builds succeed, rerun only the failed `promote` job in that same Actions run, while its nine candidate artifacts remain within their retention period; do not rerun successful `build-and-push` jobs, since a rebuild may produce a different digest and collide with immutable tags. The workflow is push-only and has no `workflow_dispatch`. Do not promote tags through local commands or other writers. This serializes repository-controlled writers, not external registry actors, and GHCR offers no compare-and-swap guarantee here. Existing manifest conflicts fail before registry inspection/writes; all planned tags are read back after promotion, including tags that already existed, before complete manifests are written. Matching existing tags are idempotent; a different digest is a hard failure. A mid-promotion failure may leave already verified tags in place, but emits no complete manifest. Never retarget or delete old tags/digests; retain previous successful release artifact for rollback.

Expand Down
4 changes: 2 additions & 2 deletions scripts/test/promote-release-contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def seed(base):
(folder / f"{name}.spdx.json").write_text(json.dumps(spdx))
(folder / f"{name}.provenance.json").write_text(json.dumps(provenance))
(folder / f"{name}.trivy.json").write_text(json.dumps(trivy))
(folder / f"{name}.version").write_text("1.0.1\n" if service.get("maven_version_property") else "\n")
(folder / f"{name}.version").write_text("1.0.2\n" if service.get("maven_version_property") else "\n")
(folder / f"{name}.source-commit").write_text(SHA + "\n")
return root

Expand Down Expand Up @@ -163,7 +163,7 @@ def main():
image = f"{PREFIX}/{service_name}"
existing_tags[f"{image}:sha-{SHA[:7]}"] = DIGEST
if service.get("maven_version_property"):
existing_tags[f"{image}:v1.0.1"] = DIGEST
existing_tags[f"{image}:v1.0.2"] = DIGEST
state.write_text(json.dumps(existing_tags)); log.write_text("")
key = f"{PREFIX}/{MATRIX[0]['name']}:sha-{SHA[:7]}"
result = call(root, bindir, state, log, "--execute", **GITHUB_WRITER, BAD_FINAL_READBACK=key)
Expand Down
2 changes: 1 addition & 1 deletion scripts/test/supply-chain-contract.sh
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ for service in owner_services:
owner_pom = repo / 'services' / service['module'].split('/', 1)[0] / 'pom.xml'
owner_properties = ET.parse(owner_pom).getroot().find('m:properties', ns)
owner_version = owner_properties.findtext(f'm:{prop}', namespaces=ns)
assert root_version == owner_version == '1.0.1', f'{service["name"]}: release version mismatch ({root_version!r} != {owner_version!r})'
assert root_version == owner_version == '1.0.2', f'{service["name"]}: release version mismatch ({root_version!r} != {owner_version!r})'
assert 'actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333' in workflow
print('digest-only candidates, common normalized repo and all-service promote gate: PASS')
scan = workflow.split(' - name: Scan pushed candidate\n', 1)[1].split(' - name:', 1)[0]
Expand Down
2 changes: 1 addition & 1 deletion services/admin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<!-- Authoritative release version of this owner service; bump independently
to release it without touching other services. Cross-service test
dependencies resolve the default copy in the root pom. -->
<service.version.admin>1.0.1</service.version.admin>
<service.version.admin>1.0.2</service.version.admin>
</properties>
<artifactId>backend-admin</artifactId>
<version>${service.version.admin}</version>
Expand Down
2 changes: 1 addition & 1 deletion services/app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<!-- Authoritative release version of this owner service; bump independently
to release it without touching other services. Cross-service test
dependencies resolve the default copy in the root pom. -->
<service.version.app>1.0.1</service.version.app>
<service.version.app>1.0.2</service.version.app>
</properties>
<artifactId>backend-app</artifactId>
<version>${service.version.app}</version>
Expand Down
2 changes: 1 addition & 1 deletion services/auth/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<!-- Authoritative release version of this owner service; bump independently
to release it without touching other services. Cross-service test
dependencies resolve the default copy in the root pom. -->
<service.version.auth>1.0.1</service.version.auth>
<service.version.auth>1.0.2</service.version.auth>
</properties>
<artifactId>backend-auth</artifactId>
<version>${service.version.auth}</version>
Expand Down
2 changes: 1 addition & 1 deletion services/judge/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<!-- Authoritative release version of this owner service; bump independently
to release it without touching other services. Cross-service test
dependencies resolve the default copy in the root pom. -->
<service.version.judge>1.0.1</service.version.judge>
<service.version.judge>1.0.2</service.version.judge>
</properties>

<artifactId>backend-judge</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion services/notification/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<!-- Authoritative release version of this owner service; bump independently
to release it without touching other services. Cross-service test
dependencies resolve the default copy in the root pom. -->
<service.version.notification>1.0.1</service.version.notification>
<service.version.notification>1.0.2</service.version.notification>
</properties>
<artifactId>backend-notification</artifactId>
<version>${service.version.notification}</version>
Expand Down
14 changes: 7 additions & 7 deletions services/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@
<!-- Per-service release versions: bump individually to release one owner
service (its image tag) independently of the shared platform modules.
Consumed by docker-publish.yml to add a v<version> GHCR tag. -->
<service.version.auth>1.0.1</service.version.auth>
<service.version.admin>1.0.1</service.version.admin>
<service.version.app>1.0.1</service.version.app>
<service.version.submission>1.0.1</service.version.submission>
<service.version.search>1.0.1</service.version.search>
<service.version.notification>1.0.1</service.version.notification>
<service.version.judge>1.0.1</service.version.judge>
<service.version.auth>1.0.2</service.version.auth>
<service.version.admin>1.0.2</service.version.admin>
<service.version.app>1.0.2</service.version.app>
<service.version.submission>1.0.2</service.version.submission>
<service.version.search>1.0.2</service.version.search>
<service.version.notification>1.0.2</service.version.notification>
<service.version.judge>1.0.2</service.version.judge>
<java.version>17</java.version>
<!-- Security fixes newer than the Spring Boot dependency BOM. -->
<jackson-2-bom.version>2.21.7</jackson-2-bom.version>
Expand Down
2 changes: 1 addition & 1 deletion services/search/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<!-- Authoritative release version of this owner service; bump independently
to release it without touching other services. Cross-service test
dependencies resolve the default copy in the root pom. -->
<service.version.search>1.0.1</service.version.search>
<service.version.search>1.0.2</service.version.search>
</properties>

<artifactId>backend-search</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion services/submission/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<!-- Authoritative release version of this owner service; bump independently
to release it without touching other services. Cross-service test
dependencies resolve the default copy in the root pom. -->
<service.version.submission>1.0.1</service.version.submission>
<service.version.submission>1.0.2</service.version.submission>
</properties>

<artifactId>backend-submission</artifactId>
Expand Down
Loading