Vulnerability Management

PMAP for the DevSecOps Engineer

By PMAP Security Team 18 min read

DevSecOps engineers live in the gap between two systems that were never designed to talk to each other. On one side sits the delivery pipeline, where commits, builds, and pull requests move fast and gate on automated checks. On the other side sits the security program, where findings pile up, get triaged by hand, and surface days or weeks after the code that produced them already shipped. The engineer’s job is to close that gap without slowing delivery down and without bolting on a brittle pile of glue scripts that nobody else can maintain.

PMAP approaches this from the integration layer outward. It treats CI/CD pipelines as first-class event sources, normalizes what they send into a common shape, and lets you respond to those events with automation that runs reliably under load. This article walks through how a DevSecOps engineer wires scans, gates, and runbooks into a real delivery flow, and where the platform draws the line between “embed security in the pipeline” and “drown the pipeline in noise.”

If you want the broader category context first, the security integration layer pillar explains how PMAP connects scanners, ITSM, and pipelines into one hub. The vulnerability management automation pillar covers the automation engine in depth. This page stays in the engineer’s seat: pipelines, webhooks, gates, and event-driven response.

Where DevSecOps Breaks Down Without a Platform

Most teams start their DevSecOps journey by adding a SAST or SCA step to a pipeline. That step runs, prints results to a build log, and maybe fails the job on a high-severity finding. It feels like progress. It usually is not, because the results live nowhere durable. There is no history, no ownership, no deduplication across runs, and no way to tell whether a finding in today’s build is new or a known issue that was accepted three sprints ago.

PMAP’s integration domain exists to be that durable layer. It is described in the wiki as the platform’s universal connector hub, managing the full lifecycle of every external system PMAP speaks to, including scanner connectors, ITSM platforms, and CI/CD pipelines. A single integration record stores credentials and configuration, and the domain dispatches vendor-specific logic through a registry of connector archetypes rather than a tangle of hardcoded branches. For a DevSecOps engineer, that means you configure GitHub, GitLab, or Jenkins once and the platform knows how to receive and interpret what those systems send.

The runbook domain is the second half of the story. It is the platform’s event-triggered automation engine. A runbook is a named automation rule made of one or more trigger rules and an ordered action list. When any trigger matches an incoming platform event, the action list executes in sequence. Together, the integration hub gives you events you can trust and the runbook engine gives you actions you can take in response. The rest of this article is about wiring those two together.

Pipeline-Triggered Scans From Six CI Vendors

The first thing most engineers want is for a code change to kick off a scan automatically. PMAP supports inbound CI/CD webhooks from six pipeline vendors: GitHub, GitLab, Jenkins, Azure DevOps, Bamboo, and Bitbucket. Each one posts to a vendor-specific receiver under /api/v1/webhooks/ci/{vendor}/{integrationId}, and the platform normalizes every payload into a single internal shape called a CIEvent before handing it to the orchestrator.

This normalization matters more than it sounds. A GitHub push event, a GitLab merge request event, and a Jenkins build webhook all carry different field names and different envelope structures. By collapsing them into one CIEvent type, PMAP lets you write orchestration logic and automation once, then point any of the six vendors at it. You are not maintaining six slightly different code paths. You are maintaining one event model.

Because every supported vendor lands in the same model, mixed estates work too. A team running GitHub for application code and Jenkins for legacy build jobs can feed both into the same vulnerability program without writing a bespoke adapter for each. The six CI/CD vendors, one webhook deep dive is the feature-level companion to this section if you want the full vendor-by-vendor mapping.

HMAC-Signed Webhooks You Can Trust

An inbound webhook endpoint is an attack surface. If anyone who learns the URL can forge a scan trigger or a status update, the gate is theater. PMAP verifies inbound CI hooks per vendor, using each vendor’s native signing mechanism rather than a one-size-fits-all token.

GitHub hooks are verified with X-Hub-Signature-256, an HMAC-SHA256 signature over the payload. GitLab uses an X-Gitlab-Token compared in constant time. Azure DevOps uses a Bearer token, also compared in constant time. Jenkins, Bamboo, and Bitbucket each carry their own header token or signature, again checked with constant-time comparison so the verification itself does not leak timing information. The constant-time check is a deliberate choice. A naive string comparison can let an attacker recover a secret byte by byte through timing, and the platform avoids that class of bug across all of these receivers.

The most important rule for a production deployment is the unsigned-hook policy. On a production instance, a missing secret causes the platform to reject every inbound hook unless CI_WEBHOOK_ALLOW_UNSIGNED is explicitly set to true. The default posture is to refuse unsigned traffic. As an engineer, that means you cannot accidentally ship a pipeline integration that anyone on the internet can trigger. You have to configure a secret, and if you forget, the hooks fail closed rather than open. This aligns with the guidance in the OWASP CI/CD Security Cheat Sheet, which treats webhook authentication and signature verification as a baseline control rather than an enhancement.

The Auto-Scan Orchestrator

Receiving and verifying a CI event is the input. Deciding what to do with it is the orchestrator’s job. When a CI event arrives, PMAP’s orchestrator applies a branch filter first, then fans out to pipeline triggers and SAST or SCA integrations as configured. A critical detail from the wiki is that the orchestrator always emits a runbook trigger event regardless of whether auto-scan is enabled. Even if you have not configured any automatic scans, the event still flows into the runbook engine, so your automation can react to pipeline activity on its own terms.

The branch filter is the first line of control. You do not want a scan firing on every feature branch and every experimental push. By filtering on branch, you can scope automatic scanning to the branches that matter, such as main, release branches, or whatever your team treats as a gate. Everything else still emits a runbook event, so you retain the option to handle non-gated branches differently without paying the cost of a full scan on each one.

The fan-out is where the orchestrator turns one event into the right set of actions. A single push to a watched branch can trigger a pipeline run and a SAST or SCA pull, depending on what you have wired to that integration. From the engineer’s perspective, this is the difference between writing imperative glue and declaring intent. You configure the branch filter and the targets, and the orchestrator handles the dispatch. The CI event audit endpoint, GET /{id}/ci/events, returns the last 200 CI webhook events with their type, repo, branch, commit, PR, action taken, and signature validity, so you can confirm that the orchestrator did what you expected on any given push.

Gating a Pull Request on New Findings

The check that developers actually feel is the pull request gate. This is where security stops being a report someone reads later and becomes a status that blocks or warns on a merge. PMAP exposes two endpoints for this. POST /{id}/ci/pr-comment posts a security-summary comment to a PR or MR, and POST /{id}/ci/pr-status reports a commit check status with a threshold-gated pass or fail.

The gate logic is driven by two severity lists in the integration’s auto-scan configuration: BlockOnNew and WarnOnNew. The wiki describes the rule precisely. On each CI event, the orchestrator evaluates these lists. If new findings appear at a severity that is in the block list, the platform sets the commit check to failure. If the matching severity is warn-only, it sets the check to pending. This gives you a two-tier gate. You can hard-block on new critical and high findings while merely warning on mediums, which keeps the gate strict where it counts without turning every medium-severity finding into a merge blocker that teams learn to route around.

The word that carries the most weight here is “new.” Gating on the total finding count punishes teams for inherited debt and trains them to disable the check. Gating on what a change introduces keeps the signal aligned with the developer’s actual responsibility, which is not making things worse. This is the practical core of shift-left, and the shift-left vulnerability management deep dive covers the cultural and process side of moving findings earlier in the lifecycle. The OWASP DevSecOps Guideline frames the same principle: feedback should reach the developer at the point of change, in the tool they already use.

Carrying CI/VCS Context Into Every Scan

A finding without context is hard to act on. “There is a SQL injection in the auth service” is useful. “There is a SQL injection in the auth service introduced on branch feature/login-rewrite at commit a1b2c3d in PR 482″ is actionable. PMAP tags scans triggered through the pipeline with the version control context that produced them, including commit_sha, branch_name, pr_number, repo_url, and triggered_by.

This context is what makes the PR gate honest and what makes later triage faster. When a scan is tied to a commit and a pull request, the platform can answer “what did this change introduce” rather than just “what does this scan see.” The branch and repo tags let an analyst or a remediation owner trace a finding back to the exact change set instead of guessing. For a DevSecOps engineer, this is the connective tissue that turns a scanner result into something a developer can fix without a forensic investigation. It also feeds the runbook engine, because a runbook condition can branch on the branch name or the trigger source and route a finding from main differently than one from a throwaway branch.

SAST, SCA and SBOM in the Pipeline

Application security in a pipeline is rarely just one scanner. You typically want static analysis on your own code, software composition analysis on your dependencies, and increasingly a software bill of materials for supply-chain visibility. PMAP handles the SAST and SCA tools through a connector archetype the wiki calls PullOnlyConnector, used for scheduled project-level results pulls from tools like Checkmarx One, Checkmarx SAST, Snyk, Black Duck, Sonatype, Prisma Cloud, and Fortify. Rather than expecting these tools to push every result inline, the platform pulls results at the project level on a schedule or on demand, which fits how most SAST and SCA engines actually expose their data.

For supply-chain work, the SCA capability includes SBOM export. POST /{id}/sboms pulls an SBOM from an SCA vendor in either CycloneDX or SPDX format, stores it in object storage, and persists the metadata. GET /{id}/sboms lists what you have stored. There is also a dependency-graph endpoint, GET /{id}/projects/{projectId}/dep-graph, that fetches the transitive dependency tree for an SCA project. The dependency graph matters because a vulnerable package is rarely a direct dependency. It is usually three levels down, pulled in by something you chose on purpose, and the transitive tree is what lets you see the real path. The CycloneDX specification is the format reference if you are standardizing on a single SBOM standard across your estate.

One governance rule applies across every scanner, SAST and SCA included. The wiki is explicit that PMAP never uses vendor severity directly. Each connector’s mapper produces a normalized severity, that severity flows through a configurable threshold filter, and the rule engine may override it further after import. For a DevSecOps engineer this is important because raw scanner severities are wildly inconsistent across tools. A “high” in one SAST tool is not a “high” in another. By normalizing first and letting your own rules adjust, the platform gives you one severity language to gate and report against instead of however many your tool sprawl happens to produce.

From Event to Action: Runbook Automation

Everything so far has been about getting trustworthy events into the platform. The runbook engine is about doing something with them. A runbook subscribes to platform events and runs an ordered action list when its trigger conditions match. The two triggers a DevSecOps engineer reaches for most are scan_finished and remote_scan_completed, both of which sit in the catalog of 16 supported trigger events.

The scan_finished event is especially well suited to pipeline automation because of what it carries. Its payload includes scan_id along with critical_count, high_count, medium_count, low_count, total_count, and status. That means a runbook can react to the shape of a scan result without re-querying anything. You can build a runbook that fires on scan_finished, checks whether the critical count is above zero, and then takes action: open a ticket, post to a Slack channel, comment on the PR, or escalate. The remote_scan_completed event covers scans that finished on a vendor system and were imported, carrying scan_id, integration_id, and external_scan_id, which is the right trigger when your scanning happens on Tenable, Qualys, or another remote engine rather than inline.

It is worth being precise about how a runbook differs from a finding rule, because the two get conflated. A finding rule reshapes a finding at import time, adjusting severity or applying tags as data lands. A runbook reacts to an event after the fact and can take side effects in the world, like creating a Jira ticket or sending a webhook. The runbook design feature page goes deeper on building these, but the mental model is simple: rules govern data, runbooks govern actions.

22 Actions, Retry and Circuit Breaker

A trigger is only as useful as the actions it can drive. PMAP’s runbook engine ships a catalog of 22 action types spanning several categories. On the notification side there is send_webhook, send_email, send_slack_message, send_teams_message, and a generic http_request with full control over method, URL, headers, and body. On the finding side there are mutations like change_finding_status, change_finding_severity, add_finding_tags, assign_finding, and append_comment. For ITSM there are actions to create a Jira issue, create a ServiceNow ticket, update a ticket status, and comment on a ticket. There is a trigger_scan action that creates a new scan and auto-selects a scanner for an asset class when you do not name an integration, plus generate_report, integration_sync, asset mutations, and flow-control actions.

For a pipeline engineer, the reliability features around those actions matter as much as the actions themselves. Each action carries an optional retry policy with between 1 and 20 attempts and exponential backoff, with configurable initial backoff, max backoff, and factor. Transient failures, like an ITSM endpoint that times out for a moment, do not have to sink the whole automation. The action retries on its own schedule.

The circuit breaker is the guardrail above retry. After 10 consecutive failures, a runbook auto-deactivates. The wiki describes this precisely: the breaker sets is_active to false and stamps breaker_tripped_at, and a ResetBreaker call re-enables it. This is exactly the behavior you want in a pipeline context. If a downstream system goes down hard, you do not want a runbook hammering it on every event and flooding your logs and the target with failed calls. The breaker trips, the runbook goes quiet, and an engineer resets it once the dependency is healthy again. Notably, skipped runs do not count toward the breaker threshold, because a skip from a pre-flight check or a gate is not a health signal. That distinction keeps the breaker measuring real failure rather than intentional no-ops.

Conditions Without Code

Not every event should trigger every action, and PMAP lets you express that selection without writing code. Runbook conditions are built as nested AND/OR ConditionGroup trees evaluated against the enriched event payload. You reference fields by dot path, such as finding.severity or asset.criticality, and compare them with one of 12 operators: eq, neq, gte, lte, gt, lt, contains, in, not_in, starts_with, older_than, and within_last.

This is enough expressiveness to encode real policy. “Fire only when severity is in critical or high AND the asset criticality is at or above a threshold” is a condition tree, not a script. The temporal operators older_than and within_last let you write rules about age, which is useful for catching findings that have lingered or for reacting only to recent activity. Because conditions are data rather than code, they live in version-controllable runbook definitions, they can be reviewed by people who do not write Go, and they do not require a redeploy to change.

Action configs support template variables too. The {{ field }} placeholders in an action’s configuration are resolved against the enriched event payload before the action runs. That means a Slack message or a ticket title can embed the actual finding severity, the asset hostname, or the commit that triggered the scan, pulled live from the event. You are not hardcoding values into the runbook. You are templating against the event that fired it, which keeps one runbook definition useful across every event it matches.

Reliability the Pipeline Demands

Pipelines are bursty. A busy afternoon can push a hundred commits across a dozen repos, and naive automation will either melt under the load or stampede a downstream system. PMAP’s runbook engine has three controls built for exactly this.

The first is throttling. A throttle_seconds setting prevents a runbook from re-firing within a window, so a flurry of events does not produce a flurry of identical actions. The second is the concurrency gate. A concurrency_key, which itself can be template-resolved from the event, caps how many instances of a runbook run at once. If you key concurrency on a repo or an asset, you can guarantee that two scans of the same target do not collide. The third is the durable workflow engine for long waits. Most runbooks run inline, synchronously in the handler goroutine, which is fast and simple. But some automations need to wait, using a sleep action or an await_signal action that blocks until an external signal arrives. For those, the optional go-workflows durable engine turns sleep and await_signal into durable timers and signals that survive worker restarts. A runbook that waits seven days for a remediation window does not evaporate if the worker process recycles.

This matters because the alternative is the brittle glue script every DevSecOps engineer has written and regretted: a cron job and a database table standing in for durable state, with no retry semantics and no concurrency control, failing silently at 3 a.m. The platform gives you throttle, concurrency, retry, circuit breaking, and durable waits as first-class settings rather than something you reimplement badly per integration. Every fire also produces a runbook_executions row with the trigger payload, the per-action results, the status, and timing, so when something does go wrong you have an execution history to read rather than a guess to make.

How PMAP Embeds Security in the Delivery Flow

Step back and the shape is clear. The integration domain turns six different CI vendors into one verified, normalized event stream, and it pulls in SAST, SCA, and SBOM data through connector archetypes built for how those tools actually work. The orchestrator decides what each event means, scoping scans by branch and always emitting a runbook trigger so automation can react. The PR gate turns new findings into a commit status that blocks or warns, keyed on what a change introduces rather than on inherited debt. And the runbook engine takes it from event to action, with conditions you can express without code and reliability controls a real pipeline demands.

The point is not that any single one of these is novel. Plenty of tools can post a PR comment or fire a webhook. The point is that they share one data model, one severity language, one audit trail, and one set of reliability primitives. A DevSecOps engineer building on PMAP is wiring components that already agree with each other, instead of stitching together services that each speak their own dialect. That is what “embed security in the delivery flow” means in practice: the security program and the pipeline finally run on the same events.

If you want to go deeper from here, the security integration layer pillar maps the full connector ecosystem, and the vulnerability management automation pillar covers the runbook engine end to end.

Ready to put pipeline security on autopilot? Read the runbook automation datasheet and see how event-driven response works against your own CI/CD events.

author avatar
PMAP Security Team

Newsletter

Get the next writeup in your inbox

One short email when a new case writeup or detection deep dive ships. No marketing drip, no third-party tracking.