diff --git a/.github/hooks/validate-k9.sh b/.github/hooks/validate-k9.sh new file mode 100755 index 0000000..955c6c8 --- /dev/null +++ b/.github/hooks/validate-k9.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# validate-k9.sh — pre-push K9 check, through the canonical validator. +# +# One validator per family (hyperpolymath/standards, +# docs/CONTRACTILE-DESCRIPTILE-VALIDATION.adoc): the grep checks that used to +# live here were a second validator, and they accepted files that contract +# v1.0.0 (D173) rejects. This runs 1-formats/k9/tools/k9-validate.sh from a +# standards checkout over the tracked K9 files, strict, layers L0–L2 (L0–L1 +# when nickel is not installed), as the k9-conformance lane does in CI (.github/workflows/dogfood-gate.yml). The lane +# is the gate; this is the early warning. +# +# Environment variables: +# INPUT_PATH — Repository to check (default: .) +# STANDARDS_DIR — A hyperpolymath/standards checkout +# (default: ../standards beside the repository) +# +# Exit codes: +# 0 — Every tracked K9 file passes, or no validator is available (skipped +# with a notice: CI still runs the lane) +# 1 — A file failed + +set -euo pipefail + +REPO="${INPUT_PATH:-.}" +STANDARDS_DIR="${STANDARDS_DIR:-$(cd "$REPO/.." && pwd)/standards}" +case "$STANDARDS_DIR" in + /*) ;; + *) STANDARDS_DIR="$PWD/$STANDARDS_DIR" ;; +esac +VALIDATOR="$STANDARDS_DIR/1-formats/k9/tools/k9-validate.sh" + +if [ ! -f "$VALIDATOR" ]; then + echo "::notice::K9: no standards checkout at $STANDARDS_DIR (set STANDARDS_DIR to run the validator locally); the k9-conformance lane validates in CI" + exit 0 +fi + +# L2 is the Nickel evaluation against the contract; without nickel the +# validator reports those checks as SKIPPED and refuses to call that a pass, +# so stop at L1 here and say so. The lane checks L2 in CI either way. +LAYER=L2 +if ! command -v nickel >/dev/null 2>&1; then + echo "::notice::K9: nickel is not installed, so layer L2 (Nickel semantics) is left to the CI lane; checking L0–L1" + LAYER=L1 +fi + +cd "$REPO" +mapfile -t files < <(git ls-files -- '*.k9.ncl' '*.k9' '*.k9.lock' | sort) +if [ "${#files[@]}" -eq 0 ]; then + echo "::notice::K9: no tracked K9 file" + exit 0 +fi + +errors=0 +for f in "${files[@]}"; do + echo " Validating: $f" + if ! bash "$VALIDATOR" --strict --layer "$LAYER" "$f"; then + errors=$((errors + 1)) + fi +done + +echo "K9: ${#files[@]} file(s), ${errors} failing (validator: $VALIDATOR)" +[ "$errors" -eq 0 ] || { echo "::error::K9 validation failed for ${errors} file(s)"; exit 1; } +echo "K9 validation passed." diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index 6e71572..635355b 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -13,7 +13,6 @@ workflows: '.github/workflows/dogfood-gate.yml': - 'actions/checkout@v7.0.1' - 'hyperpolymath/deed-ecosystem@main' - - 'hyperpolymath/k9-ecosystem@main' '.github/workflows/governance.yml': - 'metadatastician/standards@857ff096af11451841fb10488fed1438523973a1' '.github/workflows/guix-nix-policy.yml': @@ -95,6 +94,11 @@ dependencies: commit: 'sha1-9000827ccba6bdab643e8b6fd33ac0654aef8333' owner_id: 44036562 repo_id: 192626254 + 'actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08': + ref: 'v4.6.0' + commit: 'sha1-65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08' + owner_id: 44036562 + repo_id: 192625955 'actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f': ref: 'v7.0.0' commit: 'sha1-bbbca2ddaa5d8feaa63e36b76fdaad77386f024f' @@ -137,11 +141,6 @@ dependencies: commit: 'sha1-51f63319f592f97930c73d9c46184d20bd206393' owner_id: 26415196 repo_id: 297874902 - 'editorconfig-checker/action-editorconfig-checker@v3.0.0': - ref: 'v3.0.0' - commit: 'sha1-51f63319f592f97930c73d9c46184d20bd206393' - owner_id: 26415196 - repo_id: 297874902 'erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124': ref: 'v1.24.1' commit: 'sha1-54075bcc5e249e4758d363f27d099f55d843f124' @@ -190,11 +189,6 @@ dependencies: commit: 'sha1-2155aa26a21758f2ba119f61bc7e0e1981c106fb' owner_id: 6759885 repo_id: 1275650185 - 'hyperpolymath/k9-ecosystem@main': - ref: 'main' - commit: 'sha1-c1a34884054fabf0e9de81dbf68f4ba7874e85f1' - owner_id: 6759885 - repo_id: 1275650185 'hyperpolymath/smtp-notify-action@v0.5.1': ref: 'v0.5.1' commit: 'sha1-e384daf6167a7a7567642d6a62060106244d2413' @@ -209,16 +203,25 @@ dependencies: - 'actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9' - 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' - 'actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9' - - 'denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed' - 'dtolnay/rust-toolchain@e2a55d2ffb04f378e9626c28d38b36d230d1e12f' - - 'editorconfig-checker/action-editorconfig-checker@51f63319f592f97930c73d9c46184d20bd206393' - 'erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124' - 'github/codeql-action@b96794f015dfd88f77b49b1c93e0fa7110f94c63' - 'goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406' - 'ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc' - - 'oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6' - 'swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6' - 'webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555' + 'metadatastician/standards@857ff096af11451841fb10488fed1438523973a1': + ref: '857ff096af11451841fb10488fed1438523973a1' + commit: 'sha1-857ff096af11451841fb10488fed1438523973a1' + owner_id: 297579217 + repo_id: 1116521501 + uses: + - 'actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9' + - 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' + - 'denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed' + - 'editorconfig-checker/action-editorconfig-checker@51f63319f592f97930c73d9c46184d20bd206393' + - 'erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124' + - 'oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6' 'ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc': ref: 'v2.4.4' commit: 'sha1-2d1146689b8cda280b9bc96326124645441f03bc' @@ -239,6 +242,20 @@ dependencies: commit: 'sha1-f7dd8c54c2067bafc12ca7a55595d5ee9b75204a' owner_id: 80431187 repo_id: 475074978 + uses: + - 'actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08' + - 'slsa-framework/slsa-github-generator@v2.1.0' + - 'softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda' + 'slsa-framework/slsa-github-generator@v2.1.0': + ref: 'v2.1.0' + commit: 'sha1-f7dd8c54c2067bafc12ca7a55595d5ee9b75204a' + owner_id: 80431187 + repo_id: 475074978 + 'softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda': + ref: 'v2.2.1' + commit: 'sha1-c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda' + owner_id: 2242 + repo_id: 204253808 'softprops/action-gh-release@v3.0.3': ref: 'v3.0.3' commit: 'sha1-efb35369e0ad2afab669f228072c1b0d510eae64' @@ -249,7 +266,7 @@ dependencies: commit: 'sha1-6323deb102c322ba6fcbdcafc7e3dddab59af2b6' owner_id: 580492 repo_id: 298565987 - 'swatinem/rust-cache@v2.9.3': + 'swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0': ref: 'v2.9.3' commit: 'sha1-d1527c8f67ef9af357290475d4af4b0fab8f12e0' owner_id: 580492 @@ -259,20 +276,3 @@ dependencies: commit: 'sha1-e83874834305fe9a4a2997156cb26c5de65a8555' owner_id: 135788 repo_id: 208510314 - 'swatinem/rust-cache@d1527c8f67ef9af357290475d4af4b0fab8f12e0': - ref: 'v2.9.3' - commit: 'sha1-d1527c8f67ef9af357290475d4af4b0fab8f12e0' - owner_id: 580492 - repo_id: 298565987 - 'metadatastician/standards@857ff096af11451841fb10488fed1438523973a1': - ref: '857ff096af11451841fb10488fed1438523973a1' - commit: 'sha1-857ff096af11451841fb10488fed1438523973a1' - owner_id: 297579217 - repo_id: 1116521501 - uses: - - 'actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9' - - 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' - - 'denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed' - - 'editorconfig-checker/action-editorconfig-checker@51f63319f592f97930c73d9c46184d20bd206393' - - 'erlef/setup-beam@54075bcc5e249e4758d363f27d099f55d843f124' - - 'oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6' diff --git a/.github/workflows/dogfood-gate.yml b/.github/workflows/dogfood-gate.yml index 50ce52e..5cb375f 100644 --- a/.github/workflows/dogfood-gate.yml +++ b/.github/workflows/dogfood-gate.yml @@ -65,54 +65,58 @@ jobs: fi # --------------------------------------------------------------------------- - # Job 2: K9 contract validation + # Job 2: K9 conformance through the canonical validator (contract v1.0.0, + # D173), the same lane rsr-template-repo runs. The validator and contract + # come from a pinned standards checkout; .github/hooks/validate-k9.sh is + # the local wrapper, so CI and a pre-push run check the same files. # --------------------------------------------------------------------------- k9-validate: name: Validate K9 contracts runs-on: ubuntu-latest timeout-minutes: 15 + env: + NICKEL_VERSION: '1.18.0' + NICKEL_SHA256: '9cba4dd65ae9915ec61f73033aafcff307a377665a83fd8f530df086763318cb' steps: - name: Checkout repository uses: actions/checkout@v7.0.1 - - - name: Check for K9 files - id: detect - run: | - COUNT=$(find . \( -name '*.k9' -o -name '*.k9.ncl' \) -not -path './.git/*' | wc -l) - CONFIG_COUNT=$(find . \( -name '*.toml' -o -name '*.yaml' -o -name '*.yml' -o -name '*.json' \) \ - -not -path './.git/*' -not -path './node_modules/*' -not -path './.deno/*' \ - -not -name 'package-lock.json' -not -name 'Cargo.lock' -not -name 'deno.lock' | wc -l) - echo "k9_count=$COUNT" >> "$GITHUB_OUTPUT" - echo "config_count=$CONFIG_COUNT" >> "$GITHUB_OUTPUT" - if [ "$COUNT" -eq 0 ] && [ "$CONFIG_COUNT" -gt 0 ]; then - echo "::warning::Found $CONFIG_COUNT config files but no K9 contracts. Run k9iser to generate contracts." - fi - - - name: Validate K9 contracts - if: steps.detect.outputs.k9_count > 0 - uses: hyperpolymath/k9-ecosystem/validate-action@main with: - path: '.' - strict: 'false' + persist-credentials: false - - name: Write summary + - name: Checkout canonical K9 validator and contract + uses: actions/checkout@v7.0.1 + with: + repository: metadatastician/standards + ref: 8e48b1caade08a552646adeab66558ac43b4360d + path: .standards-k9 + sparse-checkout: 1-formats/k9 + sparse-checkout-cone-mode: true + persist-credentials: false + + - name: Install sha256-verified Nickel CLI run: | - K9_COUNT="${{ steps.detect.outputs.k9_count }}" - CFG_COUNT="${{ steps.detect.outputs.config_count }}" - if [ "$K9_COUNT" -eq 0 ]; then - cat <<'EOF' >> "$GITHUB_STEP_SUMMARY" - ## K9 Contract Validation - - :warning: **No K9 contract files found.** Repos with configuration files should have K9 contracts. - - Generate contracts with: `k9iser generate .` - EOF - else - echo "## K9 Contract Validation" >> "$GITHUB_STEP_SUMMARY" - echo "" >> "$GITHUB_STEP_SUMMARY" - echo "Validated **${K9_COUNT}** K9 contract(s) against **${CFG_COUNT}** config file(s)." >> "$GITHUB_STEP_SUMMARY" + set -euo pipefail + URL="https://github.com/tweag/nickel/releases/download/${NICKEL_VERSION}/nickel-x86_64-linux" + curl -sSfL --proto '=https' --proto-redir '=https' --tlsv1.2 --retry 3 -o "$RUNNER_TEMP/nickel" "$URL" + echo "${NICKEL_SHA256} ${RUNNER_TEMP}/nickel" | sha256sum -c - + chmod +x "$RUNNER_TEMP/nickel" + echo "$RUNNER_TEMP" >> "$GITHUB_PATH" + + - name: Validate K9 contracts (L0–L2) + run: | + set -euo pipefail + rm -rf "$RUNNER_TEMP/standards-k9" + mv "$PWD/.standards-k9" "$RUNNER_TEMP/standards-k9" + if [ ! -f "$RUNNER_TEMP/standards-k9/1-formats/k9/tools/k9-validate.sh" ]; then + echo "::error::K9 validator is missing from the standards checkout" + exit 1 + fi + if ! command -v nickel >/dev/null 2>&1; then + echo "::error::nickel is required for K9 layer L2 validation" + exit 1 fi + STANDARDS_DIR="$RUNNER_TEMP/standards-k9" bash .github/hooks/validate-k9.sh # --------------------------------------------------------------------------- # Job 3: Empty-linter — invisible character detection diff --git a/.machine_readable/self-validating/README.adoc b/.machine_readable/self-validating/README.adoc index 4aca2fd..f0e662b 100644 --- a/.machine_readable/self-validating/README.adoc +++ b/.machine_readable/self-validating/README.adoc @@ -51,7 +51,7 @@ Configuration with Nickel contracts for runtime validation. Evaluated safely wit === Hunt Level (Full Execution) -**File:** `examples/setup-repo.k9.ncl` +**File:** `examples/setup-repo.k9.ncl.in` Full execution with Just recipes. Can run shell commands and modify filesystem. @@ -72,13 +72,13 @@ Choose the appropriate security level for your use case: [source,bash] ---- # Kennel: Pure configuration -cp .machine_readable/contractiles/k9/examples/project-metadata.k9.ncl config/metadata.k9.ncl +cp .machine_readable/self-validating/examples/project-metadata.k9.ncl config/metadata.k9.ncl # Yard: Validated configuration -cp .machine_readable/contractiles/k9/examples/ci-config.k9.ncl .github/ci.k9.ncl +cp .machine_readable/self-validating/examples/ci-config.k9.ncl .github/ci.k9.ncl # Hunt: Full automation -cp .machine_readable/contractiles/k9/examples/setup-repo.k9.ncl scripts/setup.k9.ncl +cp .machine_readable/self-validating/examples/setup-repo.k9.ncl.in scripts/setup.k9.ncl # then fill its placeholders ---- === 2. Validate Components @@ -137,9 +137,9 @@ K9 contractiles integrate with other RSR standards: Use these as starting points for your own K9 components: -- `template-kennel.k9.ncl` - Pure data template -- `template-yard.k9.ncl` - Validated config template -- `template-hunt.k9.ncl` - Full execution template +- `template-kennel.k9.ncl.in` - Pure data template +- `template-yard.k9.ncl.in` - Validated config template +- `template-hunt.k9.ncl.in` - Full execution template == Dependencies diff --git a/.machine_readable/self-validating/examples/setup-repo.k9.ncl b/.machine_readable/self-validating/examples/setup-repo.k9.ncl.in similarity index 100% rename from .machine_readable/self-validating/examples/setup-repo.k9.ncl rename to .machine_readable/self-validating/examples/setup-repo.k9.ncl.in diff --git a/.machine_readable/self-validating/methodology-guard.k9.ncl b/.machine_readable/self-validating/methodology-guard.k9.ncl index ac77cad..1ad890a 100644 --- a/.machine_readable/self-validating/methodology-guard.k9.ncl +++ b/.machine_readable/self-validating/methodology-guard.k9.ncl @@ -10,9 +10,15 @@ K9! let methodology_guard = { pedigree = { - name = "methodology-guard", - version = "1.0.0", - leash = 'Kennel, + schema_version = "1.0.0", + component_type = "validator:methodology-guard", + metadata = { + name = "methodology-guard", + version = "1.0.0", + }, + security = { + leash = 'Yard, + }, }, name = "methodology-guard", version = "1.0.0", diff --git a/.machine_readable/self-validating/template-hunt.k9.ncl b/.machine_readable/self-validating/template-hunt.k9.ncl.in similarity index 100% rename from .machine_readable/self-validating/template-hunt.k9.ncl rename to .machine_readable/self-validating/template-hunt.k9.ncl.in diff --git a/.machine_readable/self-validating/template-kennel.k9.ncl b/.machine_readable/self-validating/template-kennel.k9.ncl.in similarity index 100% rename from .machine_readable/self-validating/template-kennel.k9.ncl rename to .machine_readable/self-validating/template-kennel.k9.ncl.in diff --git a/.machine_readable/self-validating/template-yard.k9.ncl b/.machine_readable/self-validating/template-yard.k9.ncl.in similarity index 100% rename from .machine_readable/self-validating/template-yard.k9.ncl rename to .machine_readable/self-validating/template-yard.k9.ncl.in diff --git a/container/0.1-AI-MANIFEST.a2ml b/container/0.1-AI-MANIFEST.a2ml index ccb5bc5..6ca9858 100644 --- a/container/0.1-AI-MANIFEST.a2ml +++ b/container/0.1-AI-MANIFEST.a2ml @@ -30,7 +30,7 @@ canonical_locations: build_pipeline: "container/ct-build.sh" entrypoint: "container/entrypoint.sh" monitoring: "container/vordr.toml" - deployment: "container/deploy.k9.ncl" + deployment: "container/deploy.k9.ncl.in" example: "container/compose.example.toml" --- @@ -90,12 +90,12 @@ files: detection, resource thresholds, and structured log output. depends_on: [] - - name: "deploy.k9.ncl" + - name: "deploy.k9.ncl.in" role: "Deployment Component" description: | - k9-svc deployment specification at Hunt trust level. Full pedigree - (L1-L5), environment configs, container config, and rolling - deployment strategy. + k9-svc deployment template at Hunt trust level (contract v1.0.0), + rendered by hand to deploy.k9.ncl: environment configs, container + config, and rolling deployment strategy. depends_on: ["compose.toml", "ct-build.sh"] - name: "compose.example.toml" diff --git a/container/README.adoc b/container/README.adoc index ac5196e..92c2681 100644 --- a/container/README.adoc +++ b/container/README.adoc @@ -59,8 +59,9 @@ All files use `{{PLACEHOLDER}}` tokens that are replaced by `just container-init | **vordr** runtime monitoring configuration. Defines health endpoints, crash detection, resource thresholds, and log output. -| `deploy.k9.ncl` -| **k9-svc** deployment component at Hunt trust level. Full pedigree +| `deploy.k9.ncl.in` +| **k9-svc** deployment component at Hunt trust level, kept as a template + until its registry, service name and port are filled. Full pedigree (L1--L5), environment configs (dev/staging/prod), container configuration, and rolling deployment strategy. @@ -150,7 +151,8 @@ just container-push selur-compose up --detach ---- -For k9-svc managed deployments: +For k9-svc managed deployments, render `deploy.k9.ncl.in` to `deploy.k9.ncl` +first, following its header: `just container-init` does not create it. Then: [source,bash] ---- diff --git a/container/deploy.k9.ncl b/container/deploy.k9.ncl deleted file mode 100644 index 13eeb45..0000000 --- a/container/deploy.k9.ncl +++ /dev/null @@ -1,173 +0,0 @@ -K9! -# SPDX-License-Identifier: MPL-2.0 -# deploy.k9.ncl — Proof Burrower deployment component (Hunt level) -# -# k9-svc deployment specification with full pedigree (L1-L5). -# Security Level: 'Hunt (requires cryptographic handshake for execution). -# -# WARNING: This component can execute shell commands! -# It requires explicit authorisation via the Leash system. -# -# Usage: -# nickel typecheck container/deploy.k9.ncl -# k9-svc validate container/deploy.k9.ncl -# k9-svc deploy container/deploy.k9.ncl --env production - -# The component's pedigree (self-description across five layers) -let component_pedigree = { - # ───────────────────────────────────────────────────────────── - # L1: The Snout — Identity - # ───────────────────────────────────────────────────────────── - metadata = { - name = "proof-burrower-deploy", - version = "0.0.1", - breed = "application/vnd.k9+nickel", - magic_number = "K9!", - description = "Proof Burrower deployment component (Hunt level)", - }, - - # ───────────────────────────────────────────────────────────── - # L2: The Scent — Target Environment - # ───────────────────────────────────────────────────────────── - target = { - os = 'Linux, - is_edge = false, - requires_podman = true, - min_memory_mb = 256, - }, - - # ───────────────────────────────────────────────────────────── - # L3: The Leash — Security - # ───────────────────────────────────────────────────────────── - security = { - trust_level = 'Hunt, - allow_network = true, - allow_filesystem_write = true, - allow_subprocess = true, - # In production, replace with a real Ed25519 signature. - signature = "PLACEHOLDER-SIGNATURE-REQUIRED-FOR-HUNT", - }, - - # ───────────────────────────────────────────────────────────── - # L4: The Gut — Self-Validation - # ───────────────────────────────────────────────────────────── - validation = { - checksum = "sha256:placeholder", - pedigree_version = "1.0.0", - hunt_authorized = false, # Must be set true after handshake - }, - - # ───────────────────────────────────────────────────────────── - # L5: The Muscle — Deployment Recipes - # ───────────────────────────────────────────────────────────── - recipes = { - install = "just container-build", - validate = "just container-verify", - deploy = "just container-up", - migrate = "just container-build && just container-up", - }, -} in - -# Deployment configuration -let deployment = { - # Target environments (dev / staging / production) - environments = { - dev = { - replicas = 1, - memory = "256Mi", - cpu = "100m", - image_tag = "dev", - }, - staging = { - replicas = 2, - memory = "512Mi", - cpu = "250m", - image_tag = "staging", - }, - production = { - replicas = 3, - memory = "1Gi", - cpu = "500m", - image_tag = "latest", - }, - }, - - # Container configuration - container = { - image = "{{REGISTRY}}/{{SERVICE_NAME}}", - # Required deployment input; no network port has been selected here. - port | Number, - health_check = "/health", - readiness_check = "/ready", - }, - - # Deployment strategy - strategy = { - type = "rolling", - max_surge = 1, - max_unavailable = 0, - }, -} in - -# Deployment scripts (executed at Hunt level) -let scripts = { - # Pre-deployment validation - pre_deploy = m%" -#!/bin/sh -set -eu -echo "K9: Pre-deployment validation for {{SERVICE_NAME}}..." -cd container && selur-compose verify || podman compose --file compose.toml config -echo "K9: Validation passed." -"%, - - # Deployment script - deploy = m%" -#!/bin/sh -set -eu -ENV="${1:-dev}" -echo "K9: Deploying {{SERVICE_NAME}} to $ENV environment..." -cd container -./ct-build.sh -selur-compose up --detach || podman compose --file compose.toml up --detach -echo "K9: Deployment to $ENV complete." -"%, - - # Rollback script - rollback = m%" -#!/bin/sh -set -eu -echo "K9: Rolling back {{SERVICE_NAME}} deployment..." -cd container -selur-compose down || podman compose --file compose.toml down -echo "K9: Rollback complete." -"%, -} in - -# Export the component -{ - pedigree = component_pedigree & { - name = "proof-burrower-deploy", - version = "0.0.1", - leash = 'Hunt, - signature_required = true, - }, - deployment = deployment, - scripts = scripts, - - # Security check: this component requires Hunt level - required_level = 'Hunt, - - # Warning for users - warning = m%" -WARNING: This is a Hunt-level component. - -It can execute shell commands and modify your system. -Before running, ensure you have: - -1. Reviewed the deployment scripts above -2. Verified the signature (when implemented) -3. Explicitly authorised Hunt-level execution - -Run with: k9-svc authorize container/deploy.k9.ncl && k9-svc deploy container/deploy.k9.ncl -"%, -} diff --git a/container/deploy.k9.ncl.in b/container/deploy.k9.ncl.in new file mode 100644 index 0000000..3acf51b --- /dev/null +++ b/container/deploy.k9.ncl.in @@ -0,0 +1,190 @@ +K9! +# SPDX-License-Identifier: MPL-2.0 +# deploy.k9.ncl — Proof Burrower deployment component (Hunt level) +# +# k9-svc deployment component, K9 contract v1.0.0 (D173). Shipped as +# deploy.k9.ncl.in because a template is not a component: SERVICE_NAME, +# REGISTRY and PORT are still to be chosen. Nothing renders it for you +# (`just container-init` does not): fill those three tokens, save the result +# as container/deploy.k9.ncl, and validate it as below. The structure follows +# rsr-template-repo build/container/stapeln/deploy.k9.ncl.in. +# +# WARNING: this component executes shell commands. It is 'Hunt, so a host +# runs it only with all five Hunt preconditions met, a verified signature +# among them. The signature block below is a claim until the owner signs the +# rendered file; until then the validator reports it 'Present_Unverified +# (K9-C001) and Hunt stays unauthorised. +# +# Usage (on the rendered file): +# k9-validate.sh --strict --layer L2 container/deploy.k9.ncl +# k9-svc validate container/deploy.k9.ncl +# k9-svc deploy container/deploy.k9.ncl --env production + +{ + pedigree = { + schema_version = "1.0.0", + component_type = "deployment", + + metadata = { + name = "{{SERVICE_NAME}}-deploy", + version = "0.0.1", + description = "Proof Burrower deployment component (Hunt level)", + }, + + # Target environment (extension field; contract §5.5). + target = { + os = 'Linux, + is_edge = false, + requires_podman = true, + min_memory_mb = 256, + }, + + security = { + leash = 'Hunt, + trust_level = "controlled-execution", + allow_network = true, + allow_filesystem_write = true, + allow_subprocess = true, + signature_required = true, + # Default-deny: every flag above is paid for here (contract §8.4), plus + # the deploy and rollback actions the scripts below perform. + capabilities = [ + "net.fetch", + "fs.write", + "process.spawn", + "container.run", + "deploy.apply", + "rollback.apply", + ], + }, + + warnings = [ + "This is a Hunt-level component: it executes shell commands and changes the system.", + "Review the deployment scripts before running it.", + "A signature block being present is not a signature being verified.", + "Authorise Hunt explicitly: k9-svc authorize container/deploy.k9.ncl", + ], + + side_effects = [ + "spawns container/ct-build.sh, which builds the image and packs and signs a .ctp bundle beside it", + "pulls and pushes {{REGISTRY}}/{{SERVICE_NAME}} images", + "starts, updates and stops the {{SERVICE_NAME}} stack with selur-compose, else podman compose over container/compose.toml", + "publishes the service on port {{PORT}}", + ], + + # Ed25519, presence only (K9-S009). The signing step adds payload_hash + # and signature to the rendered file; verification is K9-C001 (L3). + signature = { + algorithm = "Ed25519", + key_id = "primary", + }, + }, + + # Deployment configuration + deployment = { + # Target environments (dev / staging / production) + environments = { + dev = { + replicas = 1, + memory = "256Mi", + cpu = "100m", + image_tag = "dev", + }, + staging = { + replicas = 2, + memory = "512Mi", + cpu = "250m", + image_tag = "staging", + }, + production = { + replicas = 3, + memory = "1Gi", + cpu = "500m", + image_tag = "latest", + }, + }, + + # Container configuration + container = { + image = "{{REGISTRY}}/{{SERVICE_NAME}}", + port = {{PORT}}, + health_check = "/health", + readiness_check = "/ready", + }, + + # Deployment strategy + strategy = { + type = "rolling", + max_surge = 1, + max_unavailable = 0, + }, + }, + + # Deployment scripts (executed at Hunt level) + scripts = { + # Pre-deployment validation + pre_deploy = m%" +#!/bin/sh +set -eu +echo "K9: Pre-deployment validation for {{SERVICE_NAME}}..." +cd container +if command -v selur-compose >/dev/null 2>&1; then + selur-compose verify +else + podman compose --file compose.toml config +fi +echo "K9: Validation passed." +"%, + + # Deployment script + deploy = m%" +#!/bin/sh +set -eu +ENV="${1:-dev}" +echo "K9: Deploying {{SERVICE_NAME}} to $ENV environment..." +cd container +./ct-build.sh +if command -v selur-compose >/dev/null 2>&1; then + selur-compose up --detach +else + podman compose --file compose.toml up --detach +fi +echo "K9: Deployment to $ENV complete." +"%, + + # Rollback script + rollback = m%" +#!/bin/sh +set -eu +echo "K9: Rolling back {{SERVICE_NAME}} deployment..." +cd container +if command -v selur-compose >/dev/null 2>&1; then + selur-compose down +else + podman compose --file compose.toml down +fi +echo "K9: Rollback complete." +"%, + }, + + # Just recipes: an execution surface, which is why the leash is 'Hunt + # (K9-S011). + recipes = { + install = { + description = "Build the container image", + commands = ["just container-build"], + }, + validate = { + description = "Verify the compose configuration", + commands = ["just container-verify"], + }, + deploy = { + description = "Start the container stack", + commands = ["just container-up"], + }, + migrate = { + description = "Rebuild the image and restart the stack", + commands = ["just container-build", "just container-up"], + }, + }, +} diff --git a/coordination.k9 b/coordination.k9 index 58d42a1..76dcc26 100644 --- a/coordination.k9 +++ b/coordination.k9 @@ -3,9 +3,15 @@ K9! # Declarative session policy data; this file does not execute checks. { pedigree = { - name = "proof-burrower-coordination", - version = "0.1.0", - leash = 'Kennel, + schema_version = "1.0.0", + component_type = "session:coordination-binding", + metadata = { + name = "proof-burrower-coordination", + version = "0.1.0", + }, + security = { + leash = 'Kennel, + }, }, session_management = { source_of_truth = "standards/session-management-standards", diff --git a/session/custom-checks.k9 b/session/custom-checks.k9 index e173a6c..3044129 100644 --- a/session/custom-checks.k9 +++ b/session/custom-checks.k9 @@ -3,9 +3,15 @@ K9! # Declarative session policy data; this file does not execute checks. { pedigree = { - name = "proof-burrower-session-checks", - version = "0.1.0", - leash = 'Kennel, + schema_version = "1.0.0", + component_type = "session:custom-checks", + metadata = { + name = "proof-burrower-session-checks", + version = "0.1.0", + }, + security = { + leash = 'Kennel, + }, }, version = "0.1", checks = [ @@ -42,4 +48,4 @@ K9! requirement = "Recommended next protocol is set", }, ], -} \ No newline at end of file +}