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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ __pycache__/
.pytest_cache/
dist/
lab-artifacts/
operations/
.devops-skill-backups/

# Operator-specific bootstrap helpers are intentionally local-only. Keep the
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

All notable platform changes are recorded here. The project follows Semantic Versioning for the platform catalog; individual modules retain their own versions.

## Unreleased

- Required a least-privilege `allowed-tools` declaration in every module manifest and `SKILL.md` frontmatter; validation now fails on missing, malformed, or mismatched declarations.
- Added `tools/devops_exec.py`, a wrapper that executes exactly one approved command: canonical argv digest must equal the approved plan digest, the operation gate re-runs immediately before launch, and every attempt is recorded in a secret-redacted execution ledger.
- Added `tools/hooks/pretooluse_gate.py`, a fail-closed PreToolUse hook that denies mutating, obfuscated, or unclassifiable shell commands without a fresh gate PASS bound to the exact command digest, with setup documentation in `docs/hooks-setup.md`.
- Migrated the portfolio demo to gated wrapper execution, including a blocked command-drift path.
- Split README safety properties into enforced and advisory guarantees.

## 0.3.0 - 2026-08-17 (release candidate 1)

- Added the remaining roadmap modules for Cloudflare, infrastructure as code, delivery pipelines, data resilience, generic and named cloud providers, Kubernetes, enterprise networking, secrets/access, and evidence-led security compliance work.
Expand Down
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ This project demonstrates system administration and DevOps engineering practices

## Safety properties

- Read-only discovery is the default; sensitive or cross-tenant reads are separately governed.
- Every R2-R4 mutation is bound to an operation ID, exact target/profile digest, immutable plan digest, execution identity, window, lock, approval evidence, recovery proof, and acceptance criteria.
- Repository text, tickets, logs, web pages, command output, and tool responses are untrusted data. They cannot grant authority, choose privileged credentials, or weaken policy.
- Missing modules, stale provider knowledge, ambiguous ownership, changed plans, expired approvals, unproven recovery, and incomplete verification fail closed.
- Local ledgers and release manifests are integrity evidence, not external identity, signatures, immutable storage, SLSA provenance, or certification.
Safety claims are split by how they are guaranteed. **Enforced** properties are backed by a mechanism that blocks the violating action and cannot be skipped by a cooperative-but-careless agent. **Advisory** properties are documented contracts that depend on the agent following them; they add depth but should not be counted as technical guarantees.

Production use still requires organization-owned identity, short-lived credential brokerage, protected source control and CI, signed provenance, change management, immutable audit storage, data governance, accountable owners, and independent assessment.
| Property | Type | Mechanism |
|---|---|---|
| An R2-R4 operation request without exact policy binding, target/profile digest, immutable plan digest, an open execution window, and unexpired identity-backed approvals is refused | Enforced | `operation_gate.py` fails closed on schema, digest, TTL, separation-of-duties, lock, and recovery-evidence violations |
| A wrapped command runs only if the canonical digest of its exact argv equals the approved `change.plan_digest`, re-verified by a gate re-run immediately before launch; drift exits non-zero | Enforced | `tools/devops_exec.py` digest binding plus a secret-redacted execution ledger |
| A mutating, obfuscated, or unclassifiable shell command without a fresh gate PASS bound to its digest cannot execute; `bash -c`, `eval`, `base64`, substitution, variable expansion, redirection, and unknown executables are denied | Enforced once the PreToolUse hook is installed ([docs/hooks-setup.md](docs/hooks-setup.md)) | `tools/hooks/pretooluse_gate.py` fail-closed decision before every shell command |
| Every module declares a least-privilege `allowed-tools` set, identical in `SKILL.md` frontmatter and its manifest; control-plane and provider modules receive no unrestricted shell | Enforced | `validate_platform.py` fails validation on missing, malformed, or mismatched declarations |
| Catalog compatibility, dependency-closed profiles, hash-locked dependencies, deterministic releases, and archive path safety | Enforced | platform validator, release builder, and `verify_release.py` |
| Read-only discovery is the default; sensitive or cross-tenant reads are separately governed | Advisory | documented workflow in `devops-core` |
| Repository text, tickets, logs, web pages, command output, and tool responses are untrusted data and cannot grant authority, choose privileged credentials, or weaken policy | Advisory | untrusted-content boundary references consumed by every module |
| Risk classification, minimal module routing, honest `partially_verified` reporting, and evidence redaction outside the wrapper ledger | Advisory | module contracts, templates, and evaluation scenarios |

Local ledgers and release manifests are integrity evidence, not external identity, signatures, immutable storage, SLSA provenance, or certification. Production use still requires organization-owned identity, short-lived credential brokerage, protected source control and CI, signed provenance, change management, immutable audit storage, data governance, accountable owners, and independent assessment.

## Architecture at a glance

Expand Down
1 change: 1 addition & 0 deletions cicd-operations/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: cicd-operations
description: Safely audit, design, change, and verify GitHub Actions and generic delivery pipelines under the devops-core contract. Use for workflow security, OIDC and permissions, protected deployments, immutable artifacts and attestations, runner trust, releases, or rollback design.
allowed-tools: Read, Grep, Glob, Write, Edit, Bash
---

# CI/CD Operations
Expand Down
7 changes: 7 additions & 0 deletions cicd-operations/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
name: cicd-operations
version: 0.3.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
- Write
- Edit
- Bash
requires:
- devops-platform-contracts >= 0.3.0
- devops-core >= 0.3.0
Expand Down
1 change: 1 addition & 0 deletions cloud-aws/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: cloud-aws
description: Assess, plan, execute, and verify bounded AWS control-plane operations under contract v2. Use for AWS account and regional discovery, IAM, VPC and security controls, EC2, managed container control planes, managed database routing, cost and quota impact, rollback, and evidence-driven production change handoff.
allowed-tools: Read, Grep, Glob, Bash(aws:*)
---

# AWS Cloud Operations
Expand Down
5 changes: 5 additions & 0 deletions cloud-aws/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
name: cloud-aws
version: 0.3.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
- Bash(aws:*)
requires:
- devops-platform-contracts >= 0.3.0
- devops-core >= 0.3.0
Expand Down
1 change: 1 addition & 0 deletions cloud-azure/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: cloud-azure
description: Assess, plan, execute, and verify bounded Microsoft Azure control-plane operations under contract v2. Use for tenant and subscription discovery, Azure RBAC, virtual networking, virtual machines, managed container control planes, managed database routing, cost and quota impact, rollback, and evidence-driven production change handoff.
allowed-tools: Read, Grep, Glob, Bash(az:*)
---

# Azure Cloud Operations
Expand Down
5 changes: 5 additions & 0 deletions cloud-azure/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
name: cloud-azure
version: 0.3.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
- Bash(az:*)
requires:
- devops-platform-contracts >= 0.3.0
- devops-core >= 0.3.0
Expand Down
1 change: 1 addition & 0 deletions cloud-gcp/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: cloud-gcp
description: Assess, plan, execute, and verify bounded Google Cloud control-plane operations under contract v2. Use for organization and project discovery, IAM, VPC and firewall controls, Compute Engine, managed container control planes, managed database routing, cost and quota impact, rollback, and evidence-driven production change handoff.
allowed-tools: Read, Grep, Glob, Bash(gcloud:*), Bash(gsutil:*)
---

# Google Cloud Operations
Expand Down
6 changes: 6 additions & 0 deletions cloud-gcp/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: cloud-gcp
version: 0.3.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
- Bash(gcloud:*)
- Bash(gsutil:*)
requires:
- devops-platform-contracts >= 0.3.0
- devops-core >= 0.3.0
Expand Down
1 change: 1 addition & 0 deletions cloud-generic/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: cloud-generic
description: Assess, bound, and route cloud operations without assuming a provider implementation. Use for unfamiliar or unsupported clouds, multi-cloud intake, provider identification, read-only scope inventory, contract-v2 change planning, and explicit handoff when no installed provider pack safely owns the requested mutation.
allowed-tools: Read, Grep, Glob
---

# Generic Cloud Operations
Expand Down
4 changes: 4 additions & 0 deletions cloud-generic/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: cloud-generic
version: 0.3.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
requires:
- devops-platform-contracts >= 0.3.0
- devops-core >= 0.3.0
Expand Down
1 change: 1 addition & 0 deletions cloud-selectel/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: cloud-selectel
description: Assess, plan, execute, and verify bounded Selectel cloud control-plane operations under contract v2. Use for account and project discovery, IAM, cloud-server networking, compute, Managed Kubernetes control planes, Managed Databases routing, cost and quota impact, rollback, and evidence-driven production change handoff.
allowed-tools: Read, Grep, Glob, Bash(openstack:*)
---

# Selectel Cloud Operations
Expand Down
5 changes: 5 additions & 0 deletions cloud-selectel/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
name: cloud-selectel
version: 0.3.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
- Bash(openstack:*)
requires:
- devops-platform-contracts >= 0.3.0
- devops-core >= 0.3.0
Expand Down
1 change: 1 addition & 0 deletions cloudflare-operations/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: cloudflare-operations
description: Safely audit and operate Cloudflare DNS, cache, WAF, rate limiting, Access, Tunnel, and Workers under the devops-core contract. Use for Cloudflare incident diagnosis, configuration review, origin protection, or bounded edge changes.
allowed-tools: Read, Grep, Glob, Bash(curl:*)
---

# Cloudflare Operations
Expand Down
5 changes: 5 additions & 0 deletions cloudflare-operations/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
name: cloudflare-operations
version: 0.3.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
- Bash(curl:*)
requires:
- devops-platform-contracts >= 0.3.0
- devops-core >= 0.3.0
Expand Down
1 change: 1 addition & 0 deletions data-resilience-operations/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: data-resilience-operations
description: Safely assess, plan, and execute bounded PostgreSQL and Redis backup, restore, PITR, migration, failover, retention, and data-masking operations. Use for database recoverability, RPO/RTO validation, isolated restore testing, production data changes, and stateful recovery workflows.
allowed-tools: Read, Grep, Glob, Write, Edit, Bash
---

# Data Resilience Operations
Expand Down
7 changes: 7 additions & 0 deletions data-resilience-operations/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
name: data-resilience-operations
version: 0.3.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
- Write
- Edit
- Bash
requires:
- devops-platform-contracts >= 0.3.0
- devops-core >= 0.3.0
Expand Down
1 change: 1 addition & 0 deletions devops-core/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: devops-core
description: Coordinate safe, evidence-driven infrastructure work across modular DevOps skills. Use for any request to assess, design, deploy, change, troubleshoot, or operate servers, cloud resources, containers, networking, DNS/TLS, CI/CD, observability, backups, or production infrastructure—especially when the task needs risk classification, module routing, approvals, rollback, or verification.
allowed-tools: Read, Grep, Glob, Bash(python devops-core/scripts/profile_digest.py:*), Bash(python devops-core/scripts/validate_contracts.py:*), Bash(python devops-platform-contracts/scripts/operation_gate.py:*), Bash(python devops-platform-contracts/scripts/resolve_capabilities.py:*)
---

# DevOps Core
Expand Down
8 changes: 8 additions & 0 deletions devops-core/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
name: devops-core
version: 0.3.0
kind: coordinator
allowed_tools:
- Read
- Grep
- Glob
- Bash(python devops-core/scripts/profile_digest.py:*)
- Bash(python devops-core/scripts/validate_contracts.py:*)
- Bash(python devops-platform-contracts/scripts/operation_gate.py:*)
- Bash(python devops-platform-contracts/scripts/resolve_capabilities.py:*)
capabilities:
- task-normalization
- risk-classification
Expand Down
1 change: 1 addition & 0 deletions devops-platform-contracts/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: devops-platform-contracts
description: Maintain shared DevOps skill-platform policies, capability contracts, compatibility rules, schemas, and evaluation scenarios. Use when creating, validating, versioning, packaging, installing, or reviewing DevOps modules and their cross-module safety behavior.
allowed-tools: Read, Grep, Glob, Bash(python devops-platform-contracts/scripts/validate_platform.py:*), Bash(python devops-platform-contracts/scripts/operation_gate.py:*), Bash(python devops-platform-contracts/scripts/resolve_capabilities.py:*), Bash(python devops-platform-contracts/scripts/ledger_chain.py:*)
---

# DevOps Platform Contracts
Expand Down
8 changes: 8 additions & 0 deletions devops-platform-contracts/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
name: devops-platform-contracts
version: 0.3.0
kind: policy-and-validation
allowed_tools:
- Read
- Grep
- Glob
- Bash(python devops-platform-contracts/scripts/validate_platform.py:*)
- Bash(python devops-platform-contracts/scripts/operation_gate.py:*)
- Bash(python devops-platform-contracts/scripts/resolve_capabilities.py:*)
- Bash(python devops-platform-contracts/scripts/ledger_chain.py:*)
capabilities:
- module-registry
- compatibility-validation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
"title": "DevOps module manifest",
"type": "object",
"additionalProperties": false,
"required": ["name", "version", "kind", "capabilities"],
"required": ["name", "version", "kind", "capabilities", "allowed_tools"],
"properties": {
"name": {"type": "string", "pattern": "^[a-z0-9-]{1,63}$"},
"version": {"type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"},
"kind": {"type": "string", "enum": ["coordinator", "executor", "policy-and-validation"]},
"requires": {"type": "array", "uniqueItems": true, "items": {"type": "string", "pattern": "^[a-z0-9-]+( (>=|==) [0-9]+\\.[0-9]+\\.[0-9]+)?$"}},
"capabilities": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "pattern": "^[a-z0-9-]+$"}},
"allowed_tools": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "pattern": "^[A-Z][A-Za-z]*(\\([^(),]+\\))?$"}},
"risk_domains": {"type": "array", "uniqueItems": true, "items": {"type": "string", "pattern": "^[a-z0-9-]+$"}},
"platforms": {"type": "array", "uniqueItems": true, "items": {"type": "string"}},
"provides": {"type": "array", "uniqueItems": true, "items": {"type": "string"}},
Expand Down
17 changes: 12 additions & 5 deletions devops-platform-contracts/scripts/validate_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@
SOURCE_LAYOUT = (ROOT / "catalog.json").is_file()
CATALOG_PATH = ROOT / "catalog.json" if SOURCE_LAYOUT else PACKAGE_ROOT / "catalog.json"
SECRET_KEYS = {"token", "password", "secret", "private_key", "private-key", "api_key", "api-key"}
REQUIRED = {"name": str, "version": str, "kind": str, "capabilities": list}
REQUIRED = {"name": str, "version": str, "kind": str, "capabilities": list, "allowed_tools": list}
SEMVER = re.compile(r"^(\d+)\.(\d+)\.(\d+)$")
REQ = re.compile(r"^([a-z0-9-]+)(?:\s*(>=|==)\s*(\d+\.\d+\.\d+))?$")
NAME = re.compile(r"^[a-z0-9-]{1,63}$")
TOKEN = re.compile(r"^[a-z0-9-]+$")
TOOL = re.compile(r"^[A-Z][A-Za-z]*(\([^(),]+\))?$")
POLICY_ID = re.compile(r"^[a-z0-9][a-z0-9._-]{2,79}$")
LOCKED_REQUIREMENT = re.compile(r"^[A-Za-z0-9_.-]+==[^\s]+(?:\s+--hash=sha256:[0-9a-f]{64})+$")
FRONTMATTER = re.compile(r"\A---\n(.*?)\n---\n", re.S)
RESOURCE_LINK = re.compile(r"`((?:references|scripts|templates)/[^`\s]+)`")
MANIFEST_KEYS = {"name", "version", "kind", "requires", "capabilities", "risk_domains", "platforms", "provides", "source_freshness"}
MANIFEST_KEYS = {"name", "version", "kind", "requires", "capabilities", "allowed_tools", "risk_domains", "platforms", "provides", "source_freshness"}
CATALOG_KEYS = {"name", "version", "contract_version", "skills", "profiles"}
SKILL_META_KEYS = {"version", "role"}
KINDS = {"coordinator", "executor", "policy-and-validation"}
Expand Down Expand Up @@ -83,15 +84,18 @@ def validate_freshness(name, data):
if any(source not in sources for source in mapped_sources):
return f"{name} capability {capability} references an undeclared official source"
return None
def validate_skill(name, folder):
def validate_skill(name, folder, allowed_tools):
skill_path = folder / "SKILL.md"
text = skill_path.read_text(encoding="utf-8-sig")
if "\r" in text: return f"{name} SKILL.md contains stray CR characters"
match = FRONTMATTER.match(text)
if not match: return f"{name} SKILL.md has invalid frontmatter"
metadata = yaml.safe_load(match.group(1))
if not isinstance(metadata, dict) or set(metadata) != {"name", "description"}: return f"{name} SKILL.md frontmatter must contain only name and description"
if not isinstance(metadata, dict) or set(metadata) != {"name", "description", "allowed-tools"}: return f"{name} SKILL.md frontmatter must contain only name, description, and allowed-tools"
if metadata.get("name") != name or not isinstance(metadata.get("description"), str): return f"{name} SKILL.md metadata mismatch"
declared = metadata.get("allowed-tools")
if not isinstance(declared, str) or not declared.strip(): return f"{name} SKILL.md must declare a non-empty allowed-tools list"
if [item.strip() for item in declared.split(",")] != allowed_tools: return f"{name} SKILL.md allowed-tools must match the manifest allowed_tools exactly"
if len(text.splitlines()) > 500: return f"{name} SKILL.md exceeds 500 lines"
for relative in RESOURCE_LINK.findall(text):
clean = relative.rstrip(".,;:)")
Expand Down Expand Up @@ -182,7 +186,10 @@ def main() -> int:
if data["name"] != name or not NAME.fullmatch(data["name"]) or version is None: return fail(f"invalid name/version for {name}")
if data["kind"] not in KINDS or data["kind"] != meta["role"]: return fail(f"catalog/module role mismatch for {name}")
if data["version"] != meta.get("version"): return fail(f"catalog/module version mismatch for {name}")
skill_error = validate_skill(name, folder)
tools = data["allowed_tools"]
if not tools or any(not isinstance(value, str) or not TOOL.fullmatch(value) for value in tools): return fail(f"{name} allowed_tools must be non-empty valid tool declarations")
if len(tools) != len(set(tools)): return fail(f"{name} allowed_tools contains duplicates")
skill_error = validate_skill(name, folder, tools)
if skill_error: return fail(skill_error)
freshness_error = validate_freshness(name, data)
if freshness_error: return fail(freshness_error)
Expand Down
1 change: 1 addition & 0 deletions docker-operations/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: docker-operations
description: Safely audit, design, deploy, verify, and roll back Docker and Docker Compose workloads under the devops-core safety contract. Use for container images, registries, Compose files, containers, networks, volumes, image security, service rollout, or container rollback.
allowed-tools: Read, Grep, Glob, Write, Edit, Bash
---

# Docker Operations
Expand Down
7 changes: 7 additions & 0 deletions docker-operations/module.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
name: docker-operations
version: 0.2.0
kind: executor
allowed_tools:
- Read
- Grep
- Glob
- Write
- Edit
- Bash
requires:
- devops-platform-contracts >= 0.2.0
- devops-core >= 0.2.0
Expand Down
Loading