Skip to main content

From git init to safely-deployed Kubernetes service in four commands.

Project description

๐Ÿ›ก๏ธ DeployGuard

From git init to safely-deployed Kubernetes service in four commands.

Scaffolds hardened configs ยท Validates its own output ยท Guards your cloud bill ยท Deploys with automatic rollback

Python 3.11+ License: MIT CI PyPI Built with Typer Infra: k3s on Spot Cost: ~$6/mo


dg init payments-api
dg cost
dg provision
dg deploy

Four commands. No flags to remember. Team config in a committed file.


Contents


Why DeployGuard

Deploying a new service to Kubernetes from scratch means writing a Dockerfile, a stack of manifests, a CI pipeline, and infrastructure โ€” each a place to get something subtly wrong:

  • No resource limits โ†’ one pod starves a node and takes its neighbours down
  • No readiness probes โ†’ broken pods receive live traffic
  • :latest image tag โ†’ silent rollback to stale code
  • IAM wildcard โ†’ blast radius of a compromised key is your whole account
  • NAT Gateway added "temporarily" โ†’ +$32/mo forever

Today people either copy-paste from an old repo or have an LLM generate it and ship on hope. Almost nothing validates AI-drafted infra before it lands in production.

DeployGuard is an opinionated paved road: one command scaffolds a known-good stack with hardened configs, one checks what it'll cost before you spend a dollar, one provisions the cluster, and one deploys with a gradual traffic shift that rolls back automatically if error rates spike. It validates its own output โ€” the generator is never trusted blindly.

The meta story: DeployGuard deploys itself, the same way it deploys everything else.


Installation

Option A โ€” Homebrew tap (macOS, recommended)

brew tap toni7891/deployguard
brew trust toni7891/deployguard
brew install deployguard

macOS 27: Homebrew will print a "Tier 2 configuration" warning โ€” this is about macOS 27 being pre-release, not about DeployGuard. Safe to ignore; the install proceeds normally.

brew trust is required on macOS 27+ (Homebrew's new tap trust model). One-time step per tap.

Homebrew installs kubectl, helm, minikube, kubeconform, infracost, and dg automatically. Then add the two third-party taps for terraform and trivy:

brew tap hashicorp/tap && brew install hashicorp/tap/terraform
brew tap aquasecurity/trivy && brew install aquasecurity/trivy/trivy

Verify everything is ready:

dg doctor

Option B โ€” One-liner (macOS + Linux)

Installs all prerequisites and dg in one shot:

curl -fsSL https://raw.githubusercontent.com/toni7891/deployguard/main/scripts/install.sh | bash

The script:

  • Detects your OS (macOS / Debian-Ubuntu / RHEL-Fedora)
  • Installs Homebrew if missing (macOS)
  • Installs all external tools: kubectl, helm, minikube, kubeconform, trivy, terraform, infracost
  • Installs dg via pipx (isolated, no virtualenv management needed)
  • Prints exactly what it did and what to do next

Pin a specific version:

DEPLOYGUARD_VERSION=0.1.0 curl -fsSL https://raw.githubusercontent.com/toni7891/deployguard/main/scripts/install.sh | bash

Option C โ€” Manual

If you prefer to manage tools yourself:

1. Install prerequisites (macOS with Homebrew):

# Kubernetes toolchain
brew install kubectl helm minikube

# Validation
brew install kubeconform
brew install aquasecurity/trivy/trivy

# Infrastructure + cost
brew tap hashicorp/tap && brew install hashicorp/tap/terraform
brew install infracost

For Docker: Docker Desktop or brew install --cask docker.

Linux: dg doctor shows exact install commands for each missing tool.

2. Install DeployGuard:

# Recommended โ€” isolated install via pipx
pipx install dg-deploy

# Or from source
git clone https://github.com/toni7891/deployguard
cd deployguard
pip install -e ".[dev]"

Verify your setup

dg doctor

dg doctor checks every prerequisite and validates your config files. Fix anything marked โœ— before continuing. Example output:

Prerequisites
 โœ“  Python >= 3.11   Python 3.12.3
 โœ“  docker           Docker version 26.1.1
 โœ“  kubectl          Client Version: v1.30.0
 โœ“  helm             v3.15.0
 โœ“  minikube         minikube version: v1.33.0
 โœ“  kubeconform      Version: 0.6.7
 โœ“  trivy            Version: 0.51.1
 โœ“  terraform        Terraform v1.8.4
 โœ“  infracost        Infracost v0.10.39

Config files
 โœ“  project config   .deployguard/config.yaml  valid
 โ€“  personal config  ~/.deployguard/config.yaml not found (using defaults)

โœ… All prerequisites met.

5-Minute Local Demo

No cloud account required. Runs entirely on your machine.

# 1. Scaffold a new service (validates output before writing)
dg init payments-api

# 2. Check what it'll cost (optional but recommended)
dg cost

# 3. Bring up a local Kubernetes cluster
dg provision

# 4. Build, deploy, and watch the canary rollout
dg deploy

App is live. To open the Kubernetes dashboard:

dg dashboard

That's it. The generated service is at http://payments-api.local with:

  • /healthz liveness probe
  • /readyz readiness probe
  • Resource limits on every container
  • Non-root securityContext
  • Pinned image tag (no :latest)

Command Reference

dg doctor

Validate your machine before doing anything else.

dg doctor

Checks:

  • All required binaries are installed and reachable in PATH
  • Python version is 3.11+
  • Docker daemon is running
  • Project config (.deployguard/config.yaml) is valid YAML with known keys
  • Personal config (~/.deployguard/config.yaml) if present

No flags. Run it first on any new machine.


dg init

Scaffold a hardened FastAPI+Postgres service, then validate the output before writing it.

dg init <name>
dg init payments-api          # normal usage
dg init payments-api --no-guard   # skip guard (throwaway spike only โ€” never in CI)

Emits:

payments-api/
โ”œโ”€โ”€ Dockerfile               # multi-stage, non-root, pinned base, healthcheck
โ”œโ”€โ”€ app/
โ”‚   โ””โ”€โ”€ main.py              # FastAPI app with /healthz and /readyz
โ”œโ”€โ”€ k8s/
โ”‚   โ”œโ”€โ”€ deployment.yaml      # probes, resource limits, securityContext, non-root
โ”‚   โ”œโ”€โ”€ service.yaml
โ”‚   โ””โ”€โ”€ ingress.yaml
โ”œโ”€โ”€ infra/                   # Terraform stub for cloud resources
โ”œโ”€โ”€ .github/
โ”‚   โ””โ”€โ”€ workflows/ci.yaml    # build โ†’ test โ†’ scan โ†’ push โ†’ deploy
โ”œโ”€โ”€ .env.example             # referenced secrets (never real values)
โ”œโ”€โ”€ deployguard.yaml         # per-service manifest (name, port, health endpoints)
โ””โ”€โ”€ README.md                # generated, with exact commands to provision + deploy

The guard layer runs on the generated output โ€” if dg init produces a manifest that violates policy, it fails loudly and tells you why before writing anything to disk. The generator is never trusted blindly.

Flag Default Description
--no-guard off Skip guard validation. Escape hatch for throwaway spikes. Never use in CI.

dg cost

Static cost report on your generated infra/ before a single dollar is spent.

dg cost               # run from your service directory
dg cost infra/        # explicit path
dg cost --explain     # verbose reasoning per finding

Three sections:

  1. What will spin up โ€” parsed from terraform show -json and k8s manifests
  2. Estimated monthly cost โ€” running and paused figures from Infracost
  3. Bill-inflation risks โ€” hand-rolled cost-policy rules that editorialize about footguns

Example output:

๐Ÿ“ฆ Resources that will spin up
  aws_instance.k3s_server     t3.small  (Spot)
  aws_db_instance.postgres    db.t3.micro
  aws_route53_record.api      (DNS only)
  kubernetes pods             2 ร— payments-api

๐Ÿ’ฐ Estimated monthly cost
  Running:  $6.25/mo
  Paused:   $3.55/mo  (compute stopped, storage + DNS only)

โš ๏ธ  Cost policy warnings
  WARN  iam_least_privilege: IAM role uses Action: "*" โ€” blast radius is your
        entire account. Scope to the minimum required actions.

โœ… Under warn threshold ($10.00). Looks good.

Thresholds (warn_threshold, reject_threshold) are in your team config โ€” not flags.

Flag Default Description
path . Path to infra/ directory or Terraform root
--explain off Verbose reasoning per cost line

dg provision

Bring up a Kubernetes cluster configured for the golden path. Idempotent โ€” safe to re-run.

dg provision                  # uses target from .deployguard/config.yaml
dg provision --target local   # override: bring up minikube
dg provision --target aws     # override: spin up k3s on EC2 Spot via Terraform

Local (target: local):

  • Starts minikube with profile deployguard
  • Enables ingress addon (minikube addons enable ingress)
  • Creates namespace + resource quota
  • No cloud account needed

AWS (target: aws):

  • Runs Terraform in infra/ to provision k3s on EC2 Spot
  • Public subnet, no NAT Gateway, Elastic IP, security group
  • Same in-cluster config as local once running
  • Run dg cost before this โ€” it spins up billable infrastructure
Flag Default Description
--target from config Override config target for this run (local or aws)

dg deploy

Build โ†’ push โ†’ safe rollout with health checks and automatic rollback.

dg deploy                     # uses target from .deployguard/config.yaml
dg deploy --target local      # override target for this run
dg deploy --target aws        # deploy to AWS cluster

What happens:

  1. Build image, tag with git SHA
  2. Push to ECR (aws) or load into minikube (local)
  3. Apply a green deployment, wait for pods to be ready (live Rich panel shows STABLE/GREEN counts)
  4. Smoke test /readyz โ€” abort before touching live traffic if it fails
  5. Canary rollout: shift traffic 10% โ†’ 50% โ†’ 100% via nginx-ingress canary weights
  6. Query Prometheus error rate at each step
  7. If error rate exceeds threshold (default 1%): kubectl rollout undo and stop
  8. Write audit row (who/what/when/result) to Postgres

Live traffic never sees a broken deployment.

โ— Deploying payments-api (sha: a1b2c3d)

  Pre-check
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚  STABLE  2/2   GREEN  2/2   /readyz  โœ“     โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

  Canary rollout
  โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘  10% โ€” error rate: 0.0% โœ“
  โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘  50% โ€” error rate: 0.1% โœ“
  โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  100% โ€” error rate: 0.0% โœ“

โœ… Deployed. payments-api @ a1b2c3d
Flag Default Description
--target from config Override config target for this run (local or aws)

dg dashboard

Open the minikube Kubernetes dashboard in your browser.

dg dashboard          # open browser
dg dashboard --url    # print URL only (useful in SSH sessions)
Flag Default Description
--url off Print dashboard URL instead of opening browser

Configuration

Team config (.deployguard/config.yaml)

Commit this. Every teammate runs the same four commands and gets identical behavior โ€” no onboarding doc, no flag choreography.

# .deployguard/config.yaml

guard:
  strict: true                    # true = fail on violations (use true in CI)
                                  # false = warn only (useful during rapid local dev)
  explain: true                   # include why-it-matters + what-to-add per violation
  rules:
    require_resource_limits: error   # error | warn | off
    require_probes:          error
    require_security_context: error
    no_latest_tag:           error
    no_root_user:            error
    no_privileged_containers: error
    iam_least_privilege:     warn
  custom_rules_dir: .deployguard/rules/  # drop .py or .rego rules here; auto-loaded

cost:
  currency: USD
  warn_threshold:   10.00         # warn if monthly estimate exceeds this
  reject_threshold: 50.00         # hard stop โ€” fix IaC before provisioning
  always_explain: false           # true = verbose reasoning on every dg cost run

deploy:
  target: local                   # local | aws
  error_rate_threshold: 1.0       # % โ€” rollback trigger
  rollout_steps: [10, 50, 100]    # traffic shift steps; tune to team's risk tolerance
  smoke_timeout: 60               # seconds to wait for /readyz before aborting
  audit: true                     # write audit rows to Postgres

All fields are optional โ€” built-in defaults cover a solo dev with no config file at all.

Personal config (~/.deployguard/config.yaml)

Never commit this. Machine-specific settings only โ€” mainly which local LLM model you have pulled.

# ~/.deployguard/config.yaml

llm:
  backend: local              # local (LM Studio) | bedrock (AWS)
  model: qwen2.5-coder:14b    # whichever model you have pulled locally
  temperature: 0.2

Service manifest (deployguard.yaml)

Generated by dg init. Lives in your service root. Describes this specific service โ€” not the tool config.

# deployguard.yaml  (generated โ€” edit to match your service)

name: payments-api
port: 8080
replicas: 2
health_liveness:  /healthz
health_readiness: /readyz
namespace: deployguard

dg deploy reads this file to know what to build and where to deploy it.

Config priority order

Higher wins:

CLI flag              # single-run override
  โ†“
project config        # .deployguard/config.yaml  โ€” committed, shared
  โ†“
personal config       # ~/.deployguard/config.yaml โ€” local machine, not committed
  โ†“
built-in defaults     # sane out-of-the-box behavior, no config required

Flags are escape hatches, not the primary interface. A flag is only justified when a single run genuinely needs to diverge from the team config.

Custom policy rules

Drop .py files into .deployguard/rules/ โ€” they're auto-loaded by the guard engine. No code change, no fork required.

# .deployguard/rules/require_team_label.py

def check(manifest: dict) -> list[dict]:
    """Require team label on all workloads."""
    labels = manifest.get("metadata", {}).get("labels", {})
    if "team" not in labels:
        return [{
            "rule": "require_team_label",
            "severity": "error",
            "message": "Missing required label 'team'.",
            "explanation": (
                "The 'team' label is required for ownership tracking and alert routing. "
                "Add metadata.labels.team: <your-team-name> to this manifest."
            ),
        }]
    return []

Cluster Cost Controls

make up       # init + apply (bring cluster to running state)
make pause    # stop EC2 instance; keep EIP + DNS   (~$3.55/mo while paused)
make resume   # recreate instance and reattach EIP
make destroy  # tear down all AWS resources

dg cost derives cost figures from your actual Terraform โ€” estimates stay accurate as you change infra.


AWS Deployment

Set deploy.target: aws in .deployguard/config.yaml, then the same four commands work unchanged. dg provision runs the Terraform; dg deploy pushes to ECR.

Before you start:

# AWS credentials in environment
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_DEFAULT_REGION=us-east-1

# Check prerequisites
dg doctor

# Review what it'll cost before spinning anything up
dg cost

# Then the same four commands
dg init payments-api
dg provision          # spins up k3s on EC2 Spot โ€” billable from here
dg deploy

Running cost: ~$6.25/mo (EC2 Spot + RDS micro + Route 53, no NAT Gateway).


Standalone Claude Code Skill

The guard layer ships as a standalone Claude Code skill. No cluster, no AWS, no dg install โ€” just drop one file.

# Add to any project's Claude skills directory
mkdir -p .claude/skills/deployguard-guard
cp /path/to/deployguard/skill/SKILL.md .claude/skills/deployguard-guard/SKILL.md

Then in Claude Code:

/guard k8s/deployment.yaml
/guard infra/main.tf
/guard k8s/

Runs kubeconform schema validation, trivy image scan, and all 7 policy rules. Each violation explains what failed, why it matters, and exactly what to add.

Primary use case: paste an LLM-generated manifest and get a senior reviewer's assessment, not just a linter.


Architecture

graph LR
    subgraph CLI ["cli.py (thin โ€” no logic)"]
        doctor[dg doctor]
        init[dg init]
        cost_cmd[dg cost]
        prov[dg provision]
        deploy[dg deploy]
        dash[dg dashboard]
    end

    subgraph Core ["Core Libraries (importable)"]
        guard["guard/\n7 policy rules\nkubeconform ยท trivy"]
        cost["cost/\nterraform parse\ninfracost wrap\n8 cost-policy rules"]
        engine["engine/\nblue/green precheck\ncanary rollout\nPrometheus gate\nauto-rollback\naudit log"]
        provision["provision/\nminikube (local)\nk3s on Spot (aws)"]
        llm["llm/\nLM Studio adapter\nBedrock adapter"]
        config_mod["config.py\nsingle config reader\nCLI โ†’ project โ†’ personal โ†’ defaults"]
    end

    subgraph Consumers ["Other Consumers"]
        skill["Claude Code Skill\nskill/SKILL.md"]
        mcp["MCP Server\n(stretch)"]
        ci["GitHub Actions\nCI pipeline"]
    end

    init --> guard
    init --> llm
    cost_cmd --> cost
    prov --> provision
    deploy --> engine
    doctor --> config_mod

    skill --> guard
    mcp --> guard
    mcp --> engine
    ci --> deploy

    config_mod -.->|read by| guard
    config_mod -.->|read by| cost
    config_mod -.->|read by| engine
    config_mod -.->|read by| provision
    config_mod -.->|read by| llm

Architecture rule: guard/, cost/, and engine/ are libraries, not scripts. The CLI, the Claude Code skill, and a future MCP server all import the same modules. Core logic never lives inside CLI handlers.


How It Works (Diagrams)

Full pipeline

flowchart TD
    A([๐Ÿ‘ฉโ€๐Ÿ’ป Developer]) --> B[dg init payments-api]
    B --> C{Guard Layer}
    C -->|โŒ violations found| D[Explain: what + why + fix]
    D --> B
    C -->|โœ… all checks pass| E[Hardened scaffold written]
    E --> F[dg cost]
    F --> G{Cost Policy}
    G -->|โš ๏ธ warn threshold| H[Print risks + estimates]
    G -->|๐Ÿ›‘ reject threshold| I[Hard stop โ€” fix IaC first]
    G -->|โœ… under budget| J[dg provision]
    J --> K{Target}
    K -->|local| L[minikube + nginx-ingress]
    K -->|aws| M[k3s on EC2 Spot via Terraform]
    L & M --> N[dg deploy]
    N --> O[Build image, tag with git SHA]
    O --> P[Push to registry]
    P --> Q[Green pre-check: smoke test /readyz]
    Q -->|โŒ fails| R[Abort โ€” live traffic never touched]
    Q -->|โœ… passes| S[Canary rollout: 10% โ†’ 50% โ†’ 100%]
    S --> T{Prometheus gate}
    T -->|error rate > 1%| U[๐Ÿ”„ Auto-rollback + audit record]
    T -->|healthy at each step| V[โœ… Deployment complete]
    V --> W[Audit row โ†’ Postgres]

Rollout sequence

sequenceDiagram
    participant Dev as Developer
    participant DG as DeployGuard
    participant K8s as Kubernetes
    participant Prom as Prometheus
    participant DB as Audit Log

    Dev->>DG: dg deploy
    DG->>K8s: Build + push image (git SHA tag)
    DG->>K8s: Apply green deployment
    K8s-->>DG: Pods ready (live panel: STABLE/GREEN counts)
    DG->>K8s: Smoke test /readyz
    alt /readyz fails
        DG->>K8s: Delete green deployment
        DG-->>Dev: โŒ Abort โ€” live traffic never touched
    else /readyz passes
        DG->>K8s: Canary weight = 10%
        DG->>Prom: Query error rate (PromQL)
        alt error rate > threshold
            DG->>K8s: kubectl rollout undo
            DG->>DB: Write audit row (ROLLED_BACK)
            DG-->>Dev: ๐Ÿ”„ Auto-rollback complete
        else healthy
            DG->>K8s: Canary weight = 50%
            DG->>Prom: Query error rate
            DG->>K8s: Canary weight = 100%
            DG->>DB: Write audit row (SUCCESS)
            DG-->>Dev: โœ… Deployment complete
        end
    end

Guard Layer

flowchart LR
    A[Manifest / Terraform] --> B[YAML parse\nmalformed = named ERROR]
    B --> C[kubeconform\nschema validation]
    C --> D[trivy\nimage + IaC scan]
    D --> E[Policy rules\nPython โ†’ OPA Rego]
    E --> F{All pass?}
    F -->|yes| G[โœ… Written to disk]
    F -->|no| H[Explain each violation:\nwhat failed ยท why it matters ยท what to add]
Rule Severity Why it matters
require_resource_limits error One pod can starve a node and take neighbors down
require_probes error Broken pods receive live traffic without readiness probes
require_security_context error Missing non-root + read-only root filesystem
no_latest_tag error Silent rollback to stale code on node restart
no_root_user error Container escape โ†’ host root
no_privileged_containers error Privileged = host kernel access
iam_least_privilege warn IAM wildcard = full account blast radius

Every violation explains itself:

โœ— require_resource_limits
  Without resource limits, one misbehaving pod can consume all CPU and memory
  on its node, causing an OOM kill cascade that takes other services down with it.
  Add resources.requests and resources.limits to every container spec.

Cost Guard

Rule Default Description
NAT Gateway present reject +$32/mo + data processing fees
On-demand instead of Spot warn 3โ€“5ร— cost premium
Oversized instance warn Relative to golden-path baseline
Load balancer (ALB/NLB) warn +$16+/mo each
Uncapped RDS autoscaling warn Silent bill inflation
count/for_each on billable resource warn Multiplier on standing cost
Standing resource, no pause path reject Must have make pause or make destroy
Unattached Elastic IP warn Small but avoidable

Cost Model

State Est. monthly Notes
Running ~$6.25 EC2 Spot + RDS micro + Route 53; no NAT Gateway
Paused ~$3.55 Compute stopped; storage + DNS only
Local $0 minikube on your machine

Tech Stack

Concern Choice Why
CLI Python + Typer Clean, testable, Python-native
Config / schemas Pydantic Typed, validated config for free
Terminal UX Rich Live rollout panel โ€” half the demo
Templating Jinja2 Standard, transparent output
Manifest validation kubeconform + trivy + Python policy Deterministic guard layer
Cost estimation Infracost JSON + terraform show -json Accurate pricing โ€” wrapped, not reinvented
Deploy engine Python module + kubernetes client Reusable by CLI, skill, and MCP server
Metrics Prometheus HTTP API (PromQL) Rollout watches error rate per step
Audit SQLAlchemy โ†’ Postgres Persisted audit trail
Local cluster minikube + ingress addon Simpler than Helm ingress-nginx on local
Prod cluster k3s on EC2 Spot, no NAT Gateway ~$3โ€“5/mo
Registry ECR Already in the AWS toolchain
CI/CD GitHub Actions dg deploy called from the pipeline
LLM (stretch) LM Studio (local) or AWS Bedrock Switchable by one config line

Milestone Status

Milestone Status Description
M-1 Guard skill โœ… Done Standalone module + SKILL.md
M0 Spine โœ… Done init โ†’ provision โ†’ deploy end-to-end
M1 Harden + cost โœ… Done Hardened templates, guard in init, dg cost, full config
M2 Deploy engine โœ… Done Gradual rollout, Prometheus gate, auto-rollback, audit
M3 AWS + self-deploy โœ… Done ECR, k3s on Spot, GitHub Actions CI, self-deploy
M4 LLM + MCP ๐Ÿšง In progress LM Studio adapter working; Bedrock + MCP server pending

Testing

pip install -e ".[dev]"

pytest                              # full suite
pytest tests/test_guard.py          # guard + policy unit tests (asserts on explanation text)
pytest tests/test_smoke_e2e.py      # spine test โ€” must always pass
pytest tests/test_cost.py           # cost policy rules
pytest tests/test_config.py         # config priority order + schema validation
pytest -m "not integration"         # skip tests that require a running cluster

test_smoke_e2e.py is the branch-protection gate. No merge breaks the spine.


Project Structure

deployguard/
โ”œโ”€โ”€ cli.py               # Typer entrypoint โ€” thin; no logic lives here
โ”œโ”€โ”€ config.py            # single config reader โ€” every module reads through this
โ”œโ”€โ”€ guard/               # kubeconform + trivy + 7 policy rules with explanations
โ”œโ”€โ”€ cost/                # terraform parse + infracost + 8 cost-policy rules
โ”œโ”€โ”€ engine/              # blue/green precheck ยท canary rollout ยท rollback ยท audit
โ”œโ”€โ”€ provision/           # minikube (local) and k3s on Spot (aws)
โ”œโ”€โ”€ llm/                 # thin adapter: LM Studio local or AWS Bedrock
โ””โ”€โ”€ scaffold/            # Jinja2 templates for the golden path
skill/
โ””โ”€โ”€ SKILL.md             # standalone Claude skill โ€” wraps guard/
infra/                   # Terraform: k3s on EC2 Spot (no NAT Gateway)
tests/
โ”œโ”€โ”€ test_guard.py        # feeds bad manifests, asserts rejection + explanation text
โ”œโ”€โ”€ test_cost.py         # feeds footgun Terraform, asserts risk flagged
โ”œโ”€โ”€ test_config.py       # priority order, schema validation, custom rules
โ””โ”€โ”€ test_smoke_e2e.py    # spine test โ€” must always pass

Contributing

  1. Lock contracts first โ€” deployguard.yaml Pydantic schema, config schema, dg init output shape.
  2. test_smoke_e2e.py is the branch-protection gate โ€” never merge red.
  3. Core logic stays in libraries (guard/, cost/, engine/) โ€” not in CLI handlers.
  4. Conventional commits, one vertical slice per PR, cross-lane review.
  5. Flags are escape hatches โ€” if it can live in config, it goes in config.

License

MIT


DeployGuard deploys itself โ€” the same way it deploys everything else.

Quick Start ยท Command Reference ยท Skill ยท PRD ยท Issues

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dg_deploy-0.1.0.tar.gz (71.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dg_deploy-0.1.0-py3-none-any.whl (57.8 kB view details)

Uploaded Python 3

File details

Details for the file dg_deploy-0.1.0.tar.gz.

File metadata

  • Download URL: dg_deploy-0.1.0.tar.gz
  • Upload date:
  • Size: 71.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dg_deploy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7520c06b2272c3aeaf2dfb836bcf16427ce7dcf0115b26eb0a7945daa5a4433a
MD5 beac7b4d9173427867d57f0d7139383c
BLAKE2b-256 8997d9a292fa328e2146968f4723bf2b7f4a30a68ae139c5fa693149e8c8a7c4

See more details on using hashes here.

Provenance

The following attestation bundles were made for dg_deploy-0.1.0.tar.gz:

Publisher: publish.yaml on toni7891/DeployGuard

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dg_deploy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: dg_deploy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 57.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dg_deploy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3f712a724d3e9fe561de322dcfc976533a03ee454c9d680326946892a73fd1ca
MD5 fa6dd9cf2ec15310fc89f6fb38d8a4cc
BLAKE2b-256 449344f246b036963a343d0b37b3d71c510676c6ed6bf74a8c225c6f6aea6ed7

See more details on using hashes here.

Provenance

The following attestation bundles were made for dg_deploy-0.1.0-py3-none-any.whl:

Publisher: publish.yaml on toni7891/DeployGuard

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page