# Deployment Manifests Guide
Learn how to enable, interpret, and use deployment manifests for compliance, auditing, and operational visibility.
---
## Overview
**Deployment manifests** are immutable snapshots created at two points in your workflow:
1. **Build time** — `strata build run` captures the configuration and build outputs (artifacts, SBOM)
2. **Deploy time** — `strata deploy run` captures the full deployment record (provisioner outputs, stage results)
Think of manifests as **evidence** — a complete record of what was intended (build) and what actually happened (deploy). Together, they form your compliance audit trail.
---
## What is a Deployment Manifest?
### Build Manifest
A **build manifest** is created by `strata build run` and captures:
- **Configuration snapshot** — Full `platform.json` with all resolved values
- **Build artifacts** — Terraform, Ansible, Helm, Docker Compose files (if generated)
- **Repository state** — Git commits for all solution repositories
- **Bill of Materials** — SBOM with component versions
- **Build environment** — Timestamp, user, version, environment variables
- **Policy results** — Any policy engine outputs (if enabled)
**Purpose:** Proves what was built, by whom, when, and from which source code.
**Example use case:** Your security team asks, "What was in the build artifact that went to staging?" You show them the build manifest with the exact platform.json snapshot and commit SHAs.
### Deploy Manifest
A **deploy manifest** is created by `strata deploy run` and captures everything that was deployed:
- **Exact configuration** — Full `platform.json` snapshot
- **Pinned versions** — Git commits for all repositories
- **Infrastructure state** — Provisioners, backends, resource counts
- **Container images** — Image references with digests
- **Audit metadata** — Timestamp, user, deployment status, stage results
- **Bill of Materials** — SBOM with component versions and vulnerabilities
### The Build → Deploy Workflow
```
graph LR
A["strata build run"] -->|generates| B["Build Manifest
config + SBOM + repos"]
B -->|input to| C["strata deploy run"]
C -->|extends| D["Deploy Manifest
build manifest + results"]
D -->|compliance evidence| E["Audit Trail"]
```
**Timeline:**
1. **Build phase** → Build manifest written to `.strata/build/{deployment}/manifest.json`
2. **Review & testing** → Inspect build manifest before approving to deploy
3. **Deploy phase** → Deploy manifest written to `.strata/deployments/{deployment}/{version}/`
4. **Audit** → Both manifests available for compliance queries
---
## Why Use Deployment Manifests?
### Compliance & Audit
**Regulatory requirements (NIS2, ISAE 3402 Type 2):**
- Immutable record of infrastructure changes
- Proof of authorization (user who deployed, timestamp)
- Version pinning (exact Git commits deployed)
- Configuration snapshots for forensic analysis
**Example:** An auditor asks, "What was deployed to production on June 15?" You answer:
```bash
# Find the manifest
ls .strata/deployments/prod_deployment/v2.3.0/
# 2024-06-15T14:32:45Z.json
# Show it
jq '.spec.artifacts.repositories' 2024-06-15T14:32:45Z.json
# {
# "xyz-infrastructure": {
# "url": "git@github.com:acme/xyz-infra.git",
# "ref": "v2.3.0",
# "commit": "a1b2c3d4e5f6g7h8..." ← exact commit deployed
# }
# }
```
### Operational Visibility
**Troubleshooting:**
- Compare manifests before/after a change to identify drift
- Trace stage failures with per-stage timing and outputs
- Correlate with Git history to understand what changed
**Example:**
```bash
# What changed between two deployments?
diff <(jq '.spec.artifacts.repositories' manifest1.json) \
<(jq '.spec.artifacts.repositories' manifest2.json)
# What was the deployment status?
jq '.spec.status, .spec.stages[].status' manifest.json
# "success"
# "success"
# "success"
```
### Rollback & Recovery
**Manifest as rollback source:**
```bash
# Extract pinned versions from the last-known-good deployment
jq '.spec.artifacts.repositories | to_entries | .[].value.commit' \
previous_deployment.json > rollback_commits.txt
# Or extract the entire platform.json to reapply:
jq '.spec.artifacts.platform.content' good_manifest.json > platform.json.bak
```
---
## Setup
### 1. Enable Manifests in Configuration
Create or update your configuration file to include manifest storage:
**Local filesystem:**
```yaml
apiVersion: strata.huybrechts.xyz/v1
kind: configuration
meta:
name: local_manifest_config
spec:
manifest:
type: local
path: ".strata/deployments"
```
**GitOps (state repository):**
```yaml
apiVersion: strata.huybrechts.xyz/v1
kind: configuration
meta:
name: gitops_manifest_config
spec:
repositories:
- name: xyz-state-repo
url: git@github.com:acme/xyz-state.git
branch: main
clone: true
manifest:
type: gitops
path: "deployments"
repository: xyz-state-repo
branch: manifests
tag: true
```
### 2. Reference in Your Deployment
Add the configuration to your deployment file:
```yaml
apiVersion: strata.huybrechts.xyz/v1
kind: deployment
meta:
name: prod_deployment
spec:
configurations:
- name: local_manifest_config # or gitops_manifest_config
source:
type: local
repository: /
source_path: config/configurations/manifest_config.yaml
```
### 3. Deploy
```bash
strata deploy run -f deployments/prod.yaml
```
The manifest is written **automatically** upon completion (success or failure).
---
## Reading a Manifest
Manifests are JSON files with this structure:
```js
{
"apiVersion": "strata.huybrechts.xyz/v1",
"kind": "deployment-manifest",
"meta": {
"name": "prod_deployment",
"labels": {
"version": "2.3.0",
"environment": "production"
}
},
"spec": {
"deployment_name": "prod_deployment",
"workspace_name": "prod_workspace",
"action": "deploy",
"status": "success",
"timestamp": "2024-06-17T10:45:33Z",
"user": "ops-lead@acme.com",
"platform_version": "1.2.0",
"artifacts": {
"platform": {
"hash": "sha256:abc123...",
"path": "build/platform.json",
"content": { ... full platform.json ... }
},
"repositories": {
"xyz-infrastructure": {
"url": "git@github.com:acme/xyz-infra.git",
"ref": "v2.3.0",
"commit": "a1b2c3d4e5f6g7h8..."
},
"xyz-config": {
"url": "git@github.com:acme/xyz-config.git",
"ref": "main",
"commit": "f7g8h9i0j1k2l3m4..."
}
},
"images": [
{
"name": "traefik",
"image": "docker.io/traefik:v3.0.1",
"digest": "sha256:xyz789..."
}
],
"providers": [
{
"name": "tf_hetzner",
"type": "terraform",
"backend": {
"type": "azurerm",
"configuration": { ... }
}
}
],
"sbom": {
"path": "build/sbom.json",
"format": "cyclonedx-1.6",
"sha256": "sha256:def456...",
"component_count": 47
}
},
"stages": [
{
"name": "infrastructure",
"status": "success",
"duration_seconds": 125,
"outputs": {
"server_ip": "192.0.2.10",
"load_balancer_fqdn": "lb.example.com"
}
},
{
"name": "configure",
"status": "success",
"duration_seconds": 45,
"outputs": {}
}
]
}
}
```
### Key Fields
| Field | Purpose |
| -------------------------------- | ------------------------------------------- |
| `spec.status` | Deployment outcome (`success` or `failure`) |
| `spec.timestamp` | When deployment ran (UTC, ISO 8601) |
| `spec.user` | Who ran the deployment |
| `spec.artifacts.platform.hash` | SHA-256 of the entire configuration |
| `spec.artifacts.repositories` | Git commits for audit trail |
| `spec.artifacts.images` | Container image references + digests |
| `spec.stages[].duration_seconds` | How long each stage took |
| `spec.stages[].outputs` | Terraform outputs, Ansible facts, etc. |
| `spec.artifacts.sbom` | Bill of materials (vulnerabilities, etc.) |
---
## Common Tasks
### List All Manifests
**Using `strata manifest` CLI:**
```bash
# List all available manifests
strata manifest list
# JSON output for scripting
strata manifest list --output json
# Filter by deployment
strata manifest list --deployment prod_deployment --output json
# Show last 5 manifests
strata manifest list --last 5
```
**Manual filesystem traversal:**
**Local storage:**
```bash
# List all manifests
find .strata/deployments -name "*.json" -type f | sort
# List just production deployments, newest first
find .strata/deployments/prod_deployment -name "*.json" | sort -r | head -5
```
**GitOps storage:**
```bash
# Clone the state repo
git clone git@github.com:acme/xyz-state.git
cd xyz-state
# List deployments
find deployments -name "*.json" | sort -r
```
### View a Manifest
**Using `strata manifest` CLI:**
```bash
# Show manifest in console-friendly format
strata manifest show 2024-06-17T10:45:33Z.json
# JSON output
strata manifest show 2024-06-17T10:45:33Z.json --output json
# Query specific fields with jq
strata manifest show 2024-06-17T10:45:33Z.json --output json | \
jq '.spec.artifacts.repositories'
```
### Export Manifests for Compliance
**Create compliance evidence package:**
```bash
# Export all manifests with SBOM and platform.json
strata manifest export --output-dir ./compliance_package \
--include-sbom \
--include-platform
# Result:
# compliance_package/
# manifests/
# 2024-06-17T10:45:33Z.json
# 2024-06-16T14:22:10Z.json
# sboms/
# 2024-06-17T10:45:33Z-sbom.json
# artifacts/
# platform-2024-06-17T10:45:33Z.json
```
### Compare Two Deployments
```bash
# Export both manifests to JSON
manifest1=$(strata manifest show m1.json --output json)
manifest2=$(strata manifest show m2.json --output json)
# What repositories changed?
diff <(echo "$manifest1" | jq -r '.spec.artifacts.repositories | keys[]' | sort) \
<(echo "$manifest2" | jq -r '.spec.artifacts.repositories | keys[]' | sort)
# What commits changed?
diff <(echo "$manifest1" | jq '.spec.artifacts.repositories') \
<(echo "$manifest2" | jq '.spec.artifacts.repositories')
```
### Extract Terraform Outputs
```bash
# Get all stage outputs
jq '.spec.stages[] | select(.name == "infrastructure") | .outputs' manifest.json
# Get one specific output
jq '.spec.stages[] | select(.name == "infrastructure") | .outputs.server_ip' manifest.json
```
### Check Deployment Duration
```bash
# Total duration across all stages
jq '[.spec.stages[].duration_seconds] | add' manifest.json
# Duration per stage
jq '.spec.stages[] | {name, duration_seconds}' manifest.json
```
### Inspect SBOM
```bash
# Count components
jq '.spec.artifacts.sbom.component_count' manifest.json
# Get SBOM file
cat build/sbom.json | jq '.metadata.component'
```
### Failed Deployment Details
```bash
# Check status
jq '.spec.status' failed_manifest.json
# Which stage failed?
jq '.spec.stages[] | select(.status != "success")' failed_manifest.json
# Get error details (if captured)
jq '.spec.stages[] | select(.status != "success") | .error' failed_manifest.json
```
---
## GitOps Workflow
When using `type: gitops`, manifests are automatically committed and tagged:
```bash
# After deploy
strata deploy run -f prod.yaml
# In your state repository:
git log --oneline deployments/
# 2a3b4c5 strata: deployment manifest prod_deployment v2.3.0
# 1f2g3h4 strata: deployment manifest prod_deployment v2.2.9
# ...
# Tags are also created:
git tag -l "prod_deployment/*" | sort
# prod_deployment/v2.2.8
# prod_deployment/v2.2.9
# prod_deployment/v2.3.0
# Retrieve a manifest from a tag:
git show prod_deployment/v2.3.0:deployments/prod_deployment/v2.3.0/2024-06-17T10:45:33Z.json
```
### Downstream Automation
GitOps manifests enable automatic downstream workflows:
```bash
# Compliance scanner watches the state repo
# On new manifest commit → scan SBOM for vulnerabilities
# On new tag → generate audit report
# Example: GitHub Actions on manifest push
on:
push:
paths:
- 'deployments/**'
jobs:
compliance-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Extract SBOM from manifest
run: |
manifest=$(ls -t deployments/prod_deployment/**/*.json | head -1)
sbom_path=$(jq -r '.spec.artifacts.sbom.path' $manifest)
# Run compliance scanner on sbom_path
```
---
## Troubleshooting
### Manifest Not Written
**Check configuration:**
```bash
# Verify the configuration exists
strata validate config/configurations/manifest_config.yaml
# Check for errors in the build log
strata deploy run -f prod.yaml --verbose 2>&1 | grep -i manifest
```
**Missing `manifest` section:**
If you see `Manifest configuration not found`, the deployment doesn't reference a configuration with manifest settings. Add it:
```yaml
spec:
configurations:
- name: my_manifest_config
source:
type: local
repository: /
source_path: config/configurations/manifest.yaml
```
### GitOps Push Failed
```bash
# Check git credentials
git clone git@github.com:acme/xyz-state.git
# Verify branch exists
git ls-remote origin manifests
# Check deploy logs for git errors
strata deploy run -f prod.yaml --verbose 2>&1 | grep -i "git\|push\|branch"
```
### Manifest Has Empty `artifacts.content`
**Cause:** Platform artifact wasn't generated.
**Fix:** Run `strata build run` before `strata deploy run`:
```bash
strata build run -f prod.yaml
strata deploy run -f prod.yaml
```
### Export Audit Trail with Manifests
```bash
# Export all deployment logs plus associated manifests
strata audit export --output-dir ./audit_export --include-manifests
# Result:
# audit_export/
# deploy_logs/
# log_001.json
# log_002.json
# manifests/
# manifest_001.json
# manifest_002.json
```
---
## Build Manifests
Build manifests are generated automatically during `strata build run` and stored in `.strata/build/{deployment}/manifest.json`. They capture the state **before** deployment.
### When are Build Manifests Created?
```bash
strata build run -f deploy.yaml
# Executes: platform builder → terraform builder → ansible builder → helm builder → sbom builder
# Writes: .strata/build/{deployment}/manifest.json (contains all build artifacts + SBOM reference)
```
### Build Manifest Structure
```text
{
"apiVersion": "strata.huybrechts.xyz/v1",
"kind": "deployment-manifest",
"meta": {
"name": "prod_deployment",
"labels": {
"version": "2.3.0",
"environment": "production"
}
},
"spec": {
"deployment_name": "prod_deployment",
"workspace_name": "prod_workspace",
"action": "build",
"status": "success",
"timestamp": "2024-06-17T10:35:20Z",
"user": "devops@acme.com",
"platform_version": "1.2.0",
"build_duration_seconds": 87,
"artifacts": {
"platform": {
"hash": "sha256:abc123def456...",
"path": ".strata/build/prod_deployment/platform.json",
"content": { ...full platform.json snapshot... }
},
"repositories": {
"xyz-infrastructure": {
"url": "git@github.com:acme/xyz-infra.git",
"ref": "v2.3.0",
"commit": "a1b2c3d4e5f6g7h8..."
}
},
"sbom": {
"path": ".strata/build/prod_deployment/sbom.json",
"format": "cyclonedx-1.6",
"sha256": "sha256:xyz789..."
}
},
"policy_results": {
"status": "passed",
"policies_checked": 12,
"policies_passed": 12,
"violations": []
}
}
}
```
### Key Differences from Deploy Manifests
| Aspect | Build | Deploy |
|--------|-------|--------|
| **Trigger** | `strata build run` | `strata deploy run` |
| **Stages** | None | Multiple (infrastructure, configure, etc.) |
| **Outputs** | SBOM, policy results | Stage outputs, resource IDs, IPs |
| **Errors** | Build/validation errors | Provisioner errors |
| **Purpose** | Gate before deploying | Record what was deployed |
### Querying Build Manifests
```bash
# List only build manifests (not deployment manifests)
find .strata/build -name "manifest.json" -type f
# Show details of a build
jq '.spec | {timestamp, user, build_duration_seconds, policy_results}' \
.strata/build/prod_deployment/manifest.json
# Check if build passed all policies
jq '.spec.policy_results.status' .strata/build/prod_deployment/manifest.json
```
### Workflow: Review Build Before Deploying
```bash
# 1. Build artifacts
strata build run -f deploy/prod.yaml
# 2. Review the build manifest
strata manifest show .strata/build/prod_deployment/manifest.json
# 3. Check policy results
jq '.spec.policy_results' .strata/build/prod_deployment/manifest.json
# 4. If satisfied, deploy
strata deploy run -f deploy/prod.yaml
```
---
## Best Practices
1. **Store manifests in version control** — Commit local manifests to Git alongside your deployment configs.
2. **Tag important deployments** — Use Git tags in the state repo to mark production releases.
3. **Automate archive cleanup** — Old manifests accumulate; implement retention policies (e.g., keep last 30 days).
4. **Query manifests regularly** — Build alerts/dashboards around manifest status, duration, user, and configuration changes.
5. **Include in change tickets** — Reference the manifest commit hash in your change management system (e.g., "Changes applied in manifest commit abc123d").
6. **Review SBOM for vulnerabilities** — Extract and scan the SBOM component list for known CVEs after each deployment.
---
## See Also
- [Configuration → Manifest](../config/manifest.md) — Full schema reference
- [Models → deployment-manifest](../platform/models.md) — YAML kind specification
- [Architecture → Deployment Workflow](../platform/architecture.md) — Multi-repo design
- [Compliance & Audit](../platform/architecture.md#compliance--audit) — NIS2 / ISAE 3402 evidence