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
11 changes: 11 additions & 0 deletions .github/workflows/self-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ jobs:
- name: Run tests/*.sh and scripts/tests/*.sh
run: bash scripts/run-shell-test-suite.sh

# KYAML ratchet (YAML-POLICY Y-3, §5 step 5, standards#1024): every file
# already converted must stay KYAML. A file joins this list in the PR that
# converts it and never leaves it. Workflows are not listed here (step 6,
# standards#1025), and neither are files read by a third-party bot
# (Dependabot, FUNDING, issue forms, GitLab CI, Copilot).
- name: Converted YAML stays KYAML
run: |
set -euo pipefail
bash scripts/kyaml-format.sh --check \
_shared/container/.gatekeeper.yaml

# Not part of the offline suite: this one needs real git history, so it
# cannot live in scripts/tests/*.sh where a contributor runs it on a
# shallow or detached tree. On a pull request the comparison is the base
Expand Down
28 changes: 24 additions & 4 deletions 3-practice/YAML-POLICY.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,17 @@ These issues are now booked, in this dependency order:
`scripts/kyaml-format.sh [--check] FILE...`. It runs `yq -o kyaml` verbatim,
the one rewriter step 2's proof covers, and it refuses (exit 2) a file that
does not parse, has no final newline, or would change its data.
*Not yet a gate:* `gh actions-lock` v0.1.6 does not see a `uses:` inside a
KYAML workflow. A planted unlocked SHA stayed `valid: true`, while the same
plant in block YAML went `stale`. So workflows stay out of scope until that
tool reads flow syntax (see step 6).
It is a gate for converted non-workflow files: the Self Test workflow runs
`--check` on every file step 5 has converted (a ratchet list).
_Correction, 2026-10-01:_ an earlier version of this step said that
`gh actions-lock` v0.1.6 cannot see a `uses:` inside a KYAML workflow. That
is false. When the same ref was planted in each syntax, the result was the
same: a tag ref fails `--verify-local` in both, and a bare SHA passes in both
(the tool accepts any bare SHA as already pinned). Fix mode also left a
KYAML workflow byte-identical and kept its lock entries. The gap that
remains has nothing to do with syntax: the required
`.githooks/validate-actions-lock.sh` checks lock membership across the whole
file, not per workflow (standards#1025).
* Step 4 — `hyperpolymath/standards#1023` — owner ruling on scope.
* Step 5 — `hyperpolymath/standards#1024` — migrate non-bot estate YAML.
* Step 6 — `hyperpolymath/standards#1025` — workflows, if step 4 rules them in.
Expand Down Expand Up @@ -338,4 +345,17 @@ ruling and §5 explicitly forbids inferring scope from the probe.
| §5 step 1 discharged: GitHub Actions proven to parse KYAML
(standards#1020, closed). Steps 2–6 booked as #1021–#1025 in
dependency order and cross-referenced from §5.

| 2026-10-01
| Owner ruling D280
| §5 step 4 decided (standards#1023, closed): KYAML everywhere, workflows
included.

| 2026-10-01
| Correction + step 5 batch 1
| Step 3: the "gh actions-lock is blind to KYAML" rationale is withdrawn
(refuted by a matched control). The formatter now gates converted files in
Self Test. Step 5 batch 1 in this repo: `_shared/container/.gatekeeper.yaml`.
The remaining 73 non-workflow YAML files here are bot-read, vendored
satellite copies, or the proof's own fixtures.
|===
257 changes: 146 additions & 111 deletions _shared/container/.gatekeeper.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,114 +9,149 @@
#
# See: stapeln/container-stack/svalinn/

version: "1.0"

# ============================================================================
# Authentication
# ============================================================================
#
# Define which endpoints require authentication and at what level.

auth:
# Public endpoints — no authentication required.
# Health and readiness probes must always be public so that
# orchestrators (selur, Podman, k8s) can check service status.
public:
- path: "/health"
methods: ["GET"]
- path: "/ready"
methods: ["GET"]
- path: "/metrics"
methods: ["GET"]

# Endpoints requiring JWT or OAuth2 authentication.
# Svalinn validates the token before forwarding the request.
authenticated:
- path: "/api/v1/*"
methods: ["GET", "POST", "PUT", "DELETE"]

# ============================================================================
# Rate Limiting
# ============================================================================
#
# Protects backend services from overload. Values here are moderate
# defaults — adjust based on your service capacity.

rate_limits:
# Global limit: applied to all authenticated clients.
global:
requests_per_second: 500
burst: 1000

# Write operations: stricter limit to protect data stores.
writes:
paths: ["/api/v1/*"]
methods: ["POST", "PUT", "DELETE"]
requests_per_second: 100
burst: 200

# ============================================================================
# Container Trust
# ============================================================================
#
# Svalinn verifies that all .ctp bundles in the stack are signed by
# trusted keys and carry the required attestations.

trust:
# Only accept .ctp bundles signed by these keys.
trusted_signers:
- key_id: "{{SERVICE_NAME}}-release"
algorithm: "Ed25519"
public_key_file: "/etc/svalinn/keys/{{SERVICE_NAME}}-release.pub"

# Require these attestations on all .ctp bundles.
required_attestations:
- "source-signature"
- "sbom-complete"

# Reject unsigned or untrusted images.
reject_unsigned: true

# ============================================================================
# Request Validation
# ============================================================================
#
# Input validation at the gateway layer — catches malformed requests
# before they reach the application.

validation:
# Maximum request body size.
max_body_size: "8MB"

# Reject requests with NaN or Infinity in numeric fields.
reject_nan_inf: true

# Maximum result limit per list/search query.
max_result_limit: 500

# ============================================================================
# CORS
# ============================================================================
#
# Cross-Origin Resource Sharing policy. The defaults below allow all
# origins — restrict to your frontend domain(s) in production.

cors:
allow_origins: ["*"]
allow_methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
allow_headers: ["Content-Type", "Authorization"]
max_age: 3600

# ============================================================================
# Logging
# ============================================================================
#
# Structured logging for svalinn itself. Audit paths log all requests
# (including body hashes) for post-incident investigation.

logging:
format: "json"
level: "info"
# Log all write operations for audit trail.
audit_paths:
- "/api/v1/*"
{
version: "1.0",
# ============================================================================
# Authentication
# ============================================================================
#
# Define which endpoints require authentication and at what level.
auth: {
# Public endpoints — no authentication required.
# Health and readiness probes must always be public so that
# orchestrators (selur, Podman, k8s) can check service status.
public: [
{
path: "/health",
methods: [
"GET",
],
},
{
path: "/ready",
methods: [
"GET",
],
},
{
path: "/metrics",
methods: [
"GET",
],
},
],
# Endpoints requiring JWT or OAuth2 authentication.
# Svalinn validates the token before forwarding the request.
authenticated: [
{
path: "/api/v1/*",
methods: [
"GET",
"POST",
"PUT",
"DELETE",
],
},
],
},
# ============================================================================
# Rate Limiting
# ============================================================================
#
# Protects backend services from overload. Values here are moderate
# defaults — adjust based on your service capacity.
rate_limits: {
# Global limit: applied to all authenticated clients.
global: {
requests_per_second: 500,
burst: 1000,
},
# Write operations: stricter limit to protect data stores.
writes: {
paths: [
"/api/v1/*",
],
methods: [
"POST",
"PUT",
"DELETE",
],
requests_per_second: 100,
burst: 200,
},
},
# ============================================================================
# Container Trust
# ============================================================================
#
# Svalinn verifies that all .ctp bundles in the stack are signed by
# trusted keys and carry the required attestations.
trust: {
# Only accept .ctp bundles signed by these keys.
trusted_signers: [
{
key_id: "{{SERVICE_NAME}}-release",
algorithm: "Ed25519",
public_key_file: "/etc/svalinn/keys/{{SERVICE_NAME}}-release.pub",
},
],
# Require these attestations on all .ctp bundles.
required_attestations: [
"source-signature",
"sbom-complete",
],
# Reject unsigned or untrusted images.
reject_unsigned: true,
},
# ============================================================================
# Request Validation
# ============================================================================
#
# Input validation at the gateway layer — catches malformed requests
# before they reach the application.
validation: {
# Maximum request body size.
max_body_size: "8MB",
# Reject requests with NaN or Infinity in numeric fields.
reject_nan_inf: true,
# Maximum result limit per list/search query.
max_result_limit: 500,
},
# ============================================================================
# CORS
# ============================================================================
#
# Cross-Origin Resource Sharing policy. The defaults below allow all
# origins — restrict to your frontend domain(s) in production.
cors: {
allow_origins: [
"*",
],
allow_methods: [
"GET",
"POST",
"PUT",
"DELETE",
"OPTIONS",
],
allow_headers: [
"Content-Type",
"Authorization",
],
max_age: 3600,
},
# ============================================================================
# Logging
# ============================================================================
#
# Structured logging for svalinn itself. Audit paths log all requests
# (including body hashes) for post-incident investigation.
logging: {
format: "json",
level: "info",
# Log all write operations for audit trail.
audit_paths: [
"/api/v1/*",
],
},
}
Loading