Put a durable safety gate in front of production deployments
Accept a release from CI, run independent preflight checks, require approval only for production, deploy through your own infrastructure module, verify health, and roll back on failure.
WOML does not need a built-in connector for every cloud. A local TypeScript module can wrap your deployment API while Rust still supervises the workflow around it.
The workflow at a glance
CI webhook
→ [Verify artifact ∥ Check current service]
→ Production? ─ yes → Operations approval
└ no → Automatic authorization
→ Deploy
→ Verify health
→ Healthy? ─ yes → Complete
└ no → Roll backThe infrastructure module
Save as deployment-api.ts:
export async function deploy(
service: string,
image: string,
environment: string,
token: string,
) {
const response = await services.http.request({
method: "POST",
url: `https://deploy.example.com/environments/${environment}/releases`,
headers: { authorization: `Bearer ${token}` },
json: { service, image },
timeout: "2m",
}, { name: "deploy-release" });
return response.data;
}
export async function rollback(
environment: string,
deploymentId: string,
token: string,
) {
const response = await services.http.request({
method: "POST",
url: `https://deploy.example.com/environments/${environment}/rollbacks`,
headers: { authorization: `Bearer ${token}` },
json: { deploymentId },
timeout: "2m",
}, { name: "rollback-release" });
return response.data;
}The workflow
<woml>
<imports>
<module name="deploymentApi" from="./deployment-api.ts" />
</imports>
<workflow
id="deployment-safety-gate"
name="Deployment safety gate"
description="Authorize, deploy, verify, and roll back application releases."
version="1.0.0"
>
<config concurrency="4" timeout="2h" queue="deployments" />
<triggers>
<webhook
id="releaseCandidate"
path="/webhooks/releases"
method="POST"
auth="bearer"
secret="{{secrets.DEPLOY_WEBHOOK_TOKEN}}"
>
<schema>
{
"type": "object",
"required": ["releaseId", "service", "image", "environment", "healthUrl", "artifactUrl"],
"properties": {
"releaseId": { "type": "string" },
"service": { "type": "string" },
"image": { "type": "string" },
"environment": { "type": "string", "enum": ["staging", "production"] },
"healthUrl": { "type": "string" },
"artifactUrl": { "type": "string" }
}
}
</schema>
</webhook>
</triggers>
<steps>
<parallel id="preflight" name="Run deployment preflight" concurrency="2" on-error="wait-all">
<step id="artifact" name="Verify release artifact" retry="3">
<script>
const response = await services.http.request({
method: "HEAD",
url: context.payload.artifactUrl,
timeout: "15s"
}, { name: "verify-release-artifact" });
return { available: response.status >= 200 && response.status < 300 };
</script>
</step>
<step id="currentService" name="Check current service">
<script>
const response = await services.http.request({
url: context.payload.healthUrl,
timeout: "10s",
acceptedStatus: { minimum: 100, maximum: 599 }
}, { name: "check-current-service" });
return { status: response.status, healthy: response.ok };
</script>
</step>
</parallel>
<step id="policy" name="Evaluate release policy">
<script>
return {
production: context.payload.environment === "production",
preflightPassed: context.steps.artifact.available && context.steps.currentService.healthy
};
</script>
</step>
<choose id="authorization" name="Authorize release">
<when test="{{context.steps.policy.production}}">
<approval id="productionApproval" name="Approve production deployment" timeout="2h" on-timeout="reject">
<notify>
<slack
channels="#deployments"
bot-token="{{secrets.SLACK_BOT_TOKEN}}"
app-token="{{secrets.SLACK_APP_TOKEN}}"
/>
</notify>
<when-approved><step id="authorizeProduction"><script>return { approved: true, source: "operator" };</script></step></when-approved>
<when-rejected><step id="rejectProduction"><script>return { approved: false, source: "operator" };</script></step></when-rejected>
</approval>
<result value="{{context.steps.productionApproval}}" />
</when>
<otherwise>
<step id="authorizeStaging"><script>return { decision: "approved", source: "staging-policy" };</script></step>
<result value="{{context.steps.authorizeStaging}}" />
</otherwise>
</choose>
<step id="deploy" name="Deploy release" retry="3" retry-backoff="exponential">
<script>
if (!context.steps.policy.preflightPassed || context.steps.authorization.decision !== "approved") {
return { deployed: false, reason: "not-authorized" };
}
const deployment = await services.deploymentApi.deploy(
context.payload.service,
context.payload.image,
context.payload.environment,
secrets.DEPLOY_API_TOKEN
);
return { deployed: true, deploymentId: deployment.id };
</script>
</step>
<step id="verify" name="Verify deployed release">
<script>
if (!context.steps.deploy.deployed) return { healthy: false };
const response = await services.http.request({
url: context.payload.healthUrl,
timeout: "30s",
acceptedStatus: { minimum: 100, maximum: 599 }
}, { name: "verify-deployed-service" });
return { healthy: response.ok, status: response.status };
</script>
</step>
<choose id="outcome" name="Keep or roll back release">
<when test="{{context.steps.verify.healthy}}">
<step id="keepRelease"><script>return { status: "deployed", deploymentId: context.steps.deploy.deploymentId };</script></step>
<result value="{{context.steps.keepRelease}}" />
</when>
<otherwise>
<step id="rollbackRelease" name="Roll back failed release">
<script>
if (!context.steps.deploy.deploymentId) return { status: "not-deployed" };
await services.deploymentApi.rollback(
context.payload.environment,
context.steps.deploy.deploymentId,
secrets.DEPLOY_API_TOKEN
);
return { status: "rolled-back", deploymentId: context.steps.deploy.deploymentId };
</script>
</step>
<result value="{{context.steps.rollbackRelease}}" />
</otherwise>
</choose>
</steps>
</workflow>
</woml>Configure and run it
woml secrets set DEPLOY_WEBHOOK_TOKEN
woml secrets set DEPLOY_API_TOKEN
woml secrets set SLACK_BOT_TOKEN
woml secrets set SLACK_APP_TOKEN
woml check deployment-safety-gate.woml
woml run deployment-safety-gate.womlReplace the deployment API URLs with the API for Kubernetes, Nomad, your cloud, or your internal platform.
Why this shows WOML's range
The workflow is executable release policy. It combines arbitrary infrastructure code with parallel checks, a production-only human gate, retryable managed operations, post-deployment verification, and explicit rollback—all versioned beside the application instead of trapped in a CI or visual automation UI.