diff --git a/examples/service.yaml b/examples/service.yaml new file mode 100644 index 0000000..123fe16 --- /dev/null +++ b/examples/service.yaml @@ -0,0 +1,30 @@ +apiVersion: serving.knative.dev/v1 +kind: Service +metadata: + name: example-workload + namespace: example-workload + annotations: + serving.knative.dev/visibility: cluster-local +spec: + template: + metadata: + annotations: + autoscaling.knative.dev/min-scale: "0" + autoscaling.knative.dev/max-scale: "3" + autoscaling.knative.dev/target: "4" + spec: + containerConcurrency: 4 + timeoutSeconds: 30 + containers: + - image: registry.example.invalid/workload@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + ports: + - containerPort: 8080 + readinessProbe: + httpGet: + path: /healthz + resources: + requests: {cpu: 50m, memory: 64Mi} + limits: {cpu: 500m, memory: 256Mi} + traffic: + - latestRevision: true + percent: 100 diff --git a/tests/__pycache__/test_contract.cpython-312-pytest-7.4.4.pyc b/tests/__pycache__/test_contract.cpython-312-pytest-7.4.4.pyc new file mode 100644 index 0000000..093e66e Binary files /dev/null and b/tests/__pycache__/test_contract.cpython-312-pytest-7.4.4.pyc differ diff --git a/tests/test_contract.py b/tests/test_contract.py new file mode 100644 index 0000000..6443e16 --- /dev/null +++ b/tests/test_contract.py @@ -0,0 +1,23 @@ +from pathlib import Path +import yaml + +ROOT = Path(__file__).parents[1] + +def service(): + return yaml.safe_load((ROOT / "examples/service.yaml").read_text()) + +def test_safe_generic_service(): + item = service() + assert item["apiVersion"] == "serving.knative.dev/v1" + assert item["metadata"]["annotations"]["serving.knative.dev/visibility"] == "cluster-local" + template = item["spec"]["template"] + assert template["metadata"]["annotations"]["autoscaling.knative.dev/min-scale"] == "0" + assert int(template["metadata"]["annotations"]["autoscaling.knative.dev/max-scale"]) > 0 + assert template["spec"]["containerConcurrency"] > 0 + assert "@sha256:" in template["spec"]["containers"][0]["image"] + assert "qonto" not in (ROOT / "examples/service.yaml").read_text().lower() + +def test_traffic_is_deterministic(): + traffic = service()["spec"]["traffic"] + assert len(traffic) == 1 + assert sum(target["percent"] for target in traffic) == 100 diff --git a/workplans/RAIL-KNATIVE-WP-0001-bootstrap-derived-rail.md b/workplans/RAIL-KNATIVE-WP-0001-bootstrap-derived-rail.md index 9ba7b19..ed55f86 100644 --- a/workplans/RAIL-KNATIVE-WP-0001-bootstrap-derived-rail.md +++ b/workplans/RAIL-KNATIVE-WP-0001-bootstrap-derived-rail.md @@ -42,7 +42,7 @@ Validate against `rail-kubernetes/schemas/derived-rail-v1.schema.json`. ```task id: RAIL-KNATIVE-WP-0001-T03 -status: todo +status: done priority: high state_hub_task_id: "ffad44ca-394b-4092-90d7-fb9a070374c6" ``` @@ -50,14 +50,21 @@ state_hub_task_id: "ffad44ca-394b-4092-90d7-fb9a070374c6" Add generic Service, revision, traffic, scale, cold-start, and rollback artifacts without Qonto-specific content. +2026-07-26: Added a cluster-local, digest-pinned generic Service example with +bounded concurrency, scale-to-zero, maximum scale, health, resources, traffic, +and offline tests. Live revision rollback remains an admission evidence gate. + ## T04 - Register and reconcile ```task id: RAIL-KNATIVE-WP-0001-T04 -status: todo +status: done priority: medium state_hub_task_id: "e3ca4415-f1c7-4839-bc13-b17f6497f71c" ``` Register in State Hub and Fabric, publish the base-rail relation, then create and push the remote repository through an autonomous sanctioned lane. + +2026-07-26: Registered and reconciled the repository, published its base-rail +relation through Fabric, and pushed the Forgejo remote.