The Open Component Model (OCM) is a vendor-neutral specification for describing, packaging, and transporting software components across OCI registries and delivery pipelines. Organizations use OCM to create component versions that bundle container images, Helm charts, configuration, and other artifacts into a single, signed, and verifiable unit — enabling reproducible delivery across air-gapped environments, supply-chain attestation, and standardized handoffs between teams.
But OCM's value depends on its delivery infrastructure staying healthy. If the OCM controller misses a component version, if signing verification fails silently, or if a component transport job hangs, deployments may proceed with unverified or stale artifacts. In this tutorial you'll set up comprehensive monitoring for your OCM pipeline using Vigilmon — free tier, no credit card required.
Why OCM pipelines need external monitoring
OCM operates across multiple systems — OCI registries, signing infrastructure, and delivery controllers — each of which can fail independently.
The failure modes that external monitoring catches:
- OCI registry unreachable — OCM component versions are stored as OCI artifacts; if the registry is down, component transport fails and the pipeline stalls silently
- Signing verification failures — a component version that arrives without a valid signature may be silently accepted or silently rejected depending on policy, either allowing unverified artifacts through or blocking legitimate deliveries
- Component transport lag — the OCM controller polls for new component versions; if the controller is down or the polling interval is misconfigured, new versions are never picked up
- Replication to air-gapped targets failing — OCM supports transport to disconnected environments; if the transfer tool stops running, the air-gapped system accumulates drift without surfacing an error
- OCM controller CrashLoopBackOff — the Kubernetes-based OCM controller may crash repeatedly;
kubectl get podsshows the state but no alert fires unless monitoring is in place
What you'll need
- OCM CLI installed (
ocmbinary, from ocm.software) - An OCI registry storing OCM component versions (Harbor, GHCR, ECR, or similar)
- Optionally: the OCM controller running in a Kubernetes cluster
- A free Vigilmon account — sign up takes 30 seconds
Step 1: Monitor your OCI registry for component storage
OCM stores component versions as OCI artifacts. The registry is the foundation of every OCM operation. Monitor it directly.
Harbor registry
- Go to Monitors → New Monitor
- Choose HTTP / HTTPS
- URL:
https://harbor.example.com/api/v2.0/health - Interval: 1 minute
- Expected status:
200 - Name:
OCM Registry (Harbor) Health
GHCR
- New monitor → HTTP / HTTPS
- URL:
https://ghcr.io - Interval: 2 minutes
- Expected status:
200 - Name:
OCM Registry (GHCR) Health
Generic OCI v2 endpoint
For any OCI-compliant registry:
- New monitor → HTTP / HTTPS
- URL:
https://registry.example.com/v2/ - Expected status:
200or401 - Name:
OCM OCI Registry API
Step 2: Monitor component version transport with a heartbeat probe
OCM component version transport is the critical path: a new component version is created, signed, and pushed to the target registry. If any step fails, the delivery pipeline is broken.
Create a probe that verifies the full transport path:
#!/usr/bin/env bash
# ocm-transport-probe.sh — verify component version transport is functioning
OCM_REGISTRY="harbor.example.com"
COMPONENT_NAME="example.com/myapp"
HEARTBEAT_URL="$VIGILMON_OCM_TRANSPORT_HEARTBEAT_URL"
MAX_AGE_HOURS=2 # Alert if no new component version in 2 hours
# List component versions in the registry and find the most recent
VERSIONS=$(ocm get componentversion \
--repo OCIRegistry::https://$OCM_REGISTRY \
"$COMPONENT_NAME" \
-o json 2>/dev/null)
if [ -z "$VERSIONS" ] || [ "$VERSIONS" = "null" ]; then
echo "No component versions found for $COMPONENT_NAME in $OCM_REGISTRY"
exit 1
fi
# Get the timestamp of the most recent version
LATEST_TIME=$(echo "$VERSIONS" | jq -r '
.items | sort_by(.metadata.creationTimestamp) | last | .metadata.creationTimestamp
')
if [ -z "$LATEST_TIME" ]; then
echo "Could not parse component version timestamp"
exit 1
fi
LATEST_EPOCH=$(date -d "$LATEST_TIME" +%s 2>/dev/null || gdate -d "$LATEST_TIME" +%s)
NOW_EPOCH=$(date +%s)
AGE_HOURS=$(( (NOW_EPOCH - LATEST_EPOCH) / 3600 ))
echo "Most recent component version: $LATEST_TIME (${AGE_HOURS}h ago)"
if [ "$AGE_HOURS" -gt "$MAX_AGE_HOURS" ]; then
echo "STALE: No component version in $AGE_HOURS hours (threshold: $MAX_AGE_HOURS)"
exit 1
fi
curl -s "$HEARTBEAT_URL"
echo "OCM transport healthy"
Schedule every 30 minutes:
*/30 * * * * /opt/scripts/ocm-transport-probe.sh >> /var/log/ocm-transport-probe.log 2>&1
Create a Vigilmon Heartbeat monitor:
- Name:
OCM Component Transport - Grace period: 45 minutes
Step 3: Monitor component signing verification
OCM supports signing component versions with cosign, GPG, or x.509 certificates. A signing pipeline that silently stops signing — because a key expired, a vault connection broke, or a signing step was accidentally disabled — is the most dangerous failure mode in supply chain delivery.
Create a signing verification probe:
#!/usr/bin/env bash
# ocm-signing-probe.sh — verify that the latest component version is properly signed
OCM_REGISTRY="harbor.example.com"
COMPONENT_NAME="example.com/myapp"
SIGNING_KEY_PATH="/opt/keys/ocm-verify-public.key"
HEARTBEAT_URL="$VIGILMON_SIGNING_HEARTBEAT_URL"
# Get the latest component version number
LATEST_VERSION=$(ocm get componentversion \
--repo OCIRegistry::https://$OCM_REGISTRY \
"$COMPONENT_NAME" \
-o json 2>/dev/null | jq -r '
.items | sort_by(.metadata.creationTimestamp) | last | .spec.version
')
if [ -z "$LATEST_VERSION" ]; then
echo "Could not determine latest version of $COMPONENT_NAME"
exit 1
fi
echo "Verifying signature on $COMPONENT_NAME:$LATEST_VERSION"
# Verify the signature using OCM's verify command
ocm verify componentversion \
--repo OCIRegistry::https://$OCM_REGISTRY \
--public-key "$SIGNING_KEY_PATH" \
"$COMPONENT_NAME:$LATEST_VERSION" > /tmp/ocm-verify.log 2>&1
VERIFY_STATUS=$?
if [ $VERIFY_STATUS -ne 0 ]; then
echo "SIGNING VERIFICATION FAILED for $COMPONENT_NAME:$LATEST_VERSION:"
cat /tmp/ocm-verify.log
exit 1
fi
curl -s "$HEARTBEAT_URL"
echo "Signature verified for $COMPONENT_NAME:$LATEST_VERSION"
Schedule every 15 minutes with a Vigilmon heartbeat grace period of 25 minutes.
Step 4: Monitor the OCM controller in Kubernetes
If you run the OCM controller (from the ocm-system namespace) in a Kubernetes cluster to automate delivery, monitor its health via the Kubernetes API:
#!/usr/bin/env bash
# ocm-controller-probe.sh — check OCM controller pod health
NAMESPACE="ocm-system"
DEPLOYMENT="ocm-controller"
HEARTBEAT_URL="$VIGILMON_CONTROLLER_HEARTBEAT_URL"
# Check that the deployment has available replicas
AVAILABLE=$(kubectl get deployment "$DEPLOYMENT" \
-n "$NAMESPACE" \
-o jsonpath='{.status.availableReplicas}' 2>/dev/null)
DESIRED=$(kubectl get deployment "$DEPLOYMENT" \
-n "$NAMESPACE" \
-o jsonpath='{.spec.replicas}' 2>/dev/null)
if [ -z "$AVAILABLE" ] || [ "$AVAILABLE" -lt 1 ]; then
echo "OCM controller has no available replicas (desired: $DESIRED, available: $AVAILABLE)"
exit 1
fi
# Check for CrashLoopBackOff in controller pods
CRASHING=$(kubectl get pods \
-n "$NAMESPACE" \
-l app="$DEPLOYMENT" \
-o jsonpath='{range .items[*]}{.metadata.name}{" "}{.status.containerStatuses[0].state.waiting.reason}{"\n"}{end}' \
2>/dev/null | grep "CrashLoopBackOff" | wc -l)
if [ "$CRASHING" -gt 0 ]; then
echo "OCM controller pod(s) in CrashLoopBackOff"
exit 1
fi
echo "OCM controller healthy: $AVAILABLE/$DESIRED replicas available"
curl -s "$HEARTBEAT_URL"
Schedule every 5 minutes with a Vigilmon heartbeat grace period of 10 minutes.
You can also monitor the controller's metrics endpoint if it exposes one:
- New monitor → HTTP / HTTPS
- URL:
http://ocm-controller-metrics.ocm-system.svc.cluster.local:8080/healthz - Interval: 1 minute
- Expected status:
200 - Name:
OCM Controller Health Endpoint
Step 5: Monitor air-gapped transfer jobs
OCM's transfer tooling moves component versions from connected environments to air-gapped targets using offline bundles (CTF archives). If the transfer job stops running, the air-gapped environment freezes at the last transferred version.
Create a transfer heartbeat probe:
#!/usr/bin/env bash
# ocm-transfer-probe.sh — verify air-gapped transfer completed within SLA
TRANSFER_LOG="/var/log/ocm/transfer.log"
MAX_AGE_HOURS=24
HEARTBEAT_URL="$VIGILMON_TRANSFER_HEARTBEAT_URL"
if [ ! -f "$TRANSFER_LOG" ]; then
echo "Transfer log not found: $TRANSFER_LOG"
exit 1
fi
LAST_SUCCESS=$(grep "transfer completed" "$TRANSFER_LOG" | tail -1 | awk '{print $1, $2}')
if [ -z "$LAST_SUCCESS" ]; then
echo "No successful transfer found in log"
exit 1
fi
LAST_EPOCH=$(date -d "$LAST_SUCCESS" +%s 2>/dev/null || gdate -d "$LAST_SUCCESS" +%s)
NOW_EPOCH=$(date +%s)
AGE_HOURS=$(( (NOW_EPOCH - LAST_EPOCH) / 3600 ))
if [ "$AGE_HOURS" -gt "$MAX_AGE_HOURS" ]; then
echo "Transfer stale: last success was ${AGE_HOURS}h ago (threshold: ${MAX_AGE_HOURS}h)"
exit 1
fi
echo "Air-gapped transfer current: last success ${AGE_HOURS}h ago"
curl -s "$HEARTBEAT_URL"
Set the Vigilmon heartbeat grace period to 25 hours for a daily transfer job.
Step 6: Monitor OCI registry integration with component lookup
The simplest end-to-end test for OCM health is whether a specific component version is accessible via the OCM CLI. Run this as a scheduled probe:
#!/usr/bin/env bash
# ocm-lookup-probe.sh — end-to-end component accessibility check
OCM_REGISTRY="harbor.example.com"
COMPONENT_NAME="example.com/myapp"
EXPECTED_VERSION="${OCM_PROBE_VERSION:-latest}"
HEARTBEAT_URL="$VIGILMON_LOOKUP_HEARTBEAT_URL"
# Attempt to get component version metadata
RESULT=$(ocm get componentversion \
--repo OCIRegistry::https://$OCM_REGISTRY \
"$COMPONENT_NAME:$EXPECTED_VERSION" \
-o json 2>&1)
STATUS=$?
if [ $STATUS -ne 0 ] || echo "$RESULT" | grep -q "Error\|error\|not found"; then
echo "OCM component lookup failed for $COMPONENT_NAME:$EXPECTED_VERSION"
echo "$RESULT"
exit 1
fi
echo "OCM component accessible: $COMPONENT_NAME:$EXPECTED_VERSION"
curl -s "$HEARTBEAT_URL"
Schedule every 10 minutes with a 20-minute heartbeat grace period.
Step 7: Monitor delivery pipeline status
OCM delivery pipelines often involve a controller that reconciles ComponentVersion custom resources against a target state. Monitor the pipeline's Kubernetes resources:
#!/usr/bin/env bash
# ocm-pipeline-probe.sh — check for stuck or failed OCM deliveries
NAMESPACE="delivery"
HEARTBEAT_URL="$VIGILMON_PIPELINE_HEARTBEAT_URL"
# Check for ComponentVersion resources in Failed state
FAILED=$(kubectl get componentversion \
-n "$NAMESPACE" \
-o json 2>/dev/null | jq '
[.items[] | select(.status.conditions[]? | .type == "Ready" and .status == "False")] | length
')
if [ -z "$FAILED" ]; then
echo "Could not query ComponentVersion resources"
exit 1
fi
if [ "$FAILED" -gt 0 ]; then
echo "FAILED: $FAILED ComponentVersion resources are not Ready"
kubectl get componentversion -n "$NAMESPACE" \
--field-selector='status.conditions[0].status=False' 2>/dev/null
exit 1
fi
echo "All ComponentVersion resources Ready in namespace $NAMESPACE"
curl -s "$HEARTBEAT_URL"
Step 8: Set up alerts
Configure Vigilmon alerts for your OCM monitors:
| Monitor | Alert threshold | Notification | |---|---|---| | OCI Registry Health | 2 minutes down | Slack #platform-alerts, PagerDuty | | OCM Component Transport heartbeat | 45-minute silence | Slack #delivery-health | | OCM Signing Verification heartbeat | 25-minute silence | Slack #security-alerts, email security team | | OCM Controller heartbeat | 10-minute silence | PagerDuty | | Air-Gapped Transfer heartbeat | 25-hour silence | Slack #airgap-ops | | Component Lookup heartbeat | 20-minute silence | Slack #platform-alerts | | Pipeline Status heartbeat | 30-minute silence | Slack #delivery-health |
For the signing verification monitor, escalate immediately to the security team — a signing failure is a supply chain integrity issue.
Interpreting Vigilmon alerts for OCM
| Alert | Likely cause | First action |
|---|---|---|
| OCI Registry Health down | Registry service issue, disk full | Check registry admin panel; docker info on registry host |
| Component Transport silent | Pipeline job not running, OCM CLI error | Check cron status; run ocm-transport-probe.sh manually |
| Signing Verification silent | Signing job failed, key expired, Vault unreachable | Run probe manually; check signing key expiry; check Vault connectivity |
| OCM Controller silent | Pod CrashLoopBackOff, OOM killed | kubectl describe pod -n ocm-system; check memory limits |
| Air-Gapped Transfer silent | Transfer job not run, host down, disk full on target | Check transfer host; run transfer job manually |
| Component Lookup silent | Registry auth failure, network issue | Run ocm get componentversion manually; check registry credentials |
| Pipeline Status silent | Controller not reconciling, resource stuck | kubectl get componentversion -n delivery; check controller logs |
What's next
Once OCM monitoring is in place:
- SBOM attestation monitoring — if your OCM components include SBOM resources, add a probe that verifies the SBOM is present and parseable in each new component version
- Multi-registry transport — if you transport components to multiple registries (dev, staging, prod), create separate transport probes for each path
- Version freshness alerting — use the transport probe's age threshold to enforce delivery SLAs (e.g., alert if the production registry is more than 4 hours behind the source)
- Signing key rotation reminders — monitor your signing key expiry dates and alert 30 days in advance, independent of whether a signing failure has occurred
OCM brings consistency and verifiability to software delivery. Vigilmon makes the health of that delivery infrastructure observable, so you know immediately when a signing step breaks, a transport job stalls, or a controller silently falls behind.