Skip to content
34 changes: 31 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Set up Java
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1
with:
distribution: temurin
java-version: "21"
Expand All @@ -29,11 +29,39 @@ jobs:
uses: gradle/actions/setup-gradle@90ddb51e90a5fd9ba75f40cf85156b7b41bf76a3 # v6

- name: Build and test
run: ./gradlew clean test jar
run: ./gradlew clean test jar --no-daemon

- name: Verify distributable JAR
shell: bash
run: |
set -euo pipefail
mapfile -t jars < <(find build/libs -maxdepth 1 -type f -name 'workflowguard-*.jar' -print)
if [[ ${#jars[@]} -ne 1 ]]; then
echo "Expected exactly one WorkflowGuard JAR, found ${#jars[@]}" >&2
exit 1
fi

jar_path="${jars[0]}"
if jar tf "$jar_path" | grep -q '^burp/api/montoya/'; then
echo "The distributable JAR must not bundle Montoya API classes." >&2
exit 1
fi

duplicates="$(jar tf "$jar_path" | sort | uniq -d)"
if [[ -n "$duplicates" ]]; then
echo "Duplicate JAR entries detected:" >&2
echo "$duplicates" >&2
exit 1
fi

sha256sum "$jar_path" > "$jar_path.sha256"
sha256sum -c "$jar_path.sha256"

- name: Upload extension JAR
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: workflowguard-extension
path: build/libs/workflowguard-*.jar
path: |
build/libs/workflowguard-*.jar
build/libs/workflowguard-*.jar.sha256
if-no-files-found: error
104 changes: 104 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

jobs:
release:
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Set up Java
uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1
with:
distribution: temurin
java-version: "21"

- name: Set up Gradle
uses: gradle/actions/setup-gradle@90ddb51e90a5fd9ba75f40cf85156b7b41bf76a3 # v6

- name: Validate tag and project version
id: version
shell: bash
run: |
set -euo pipefail
project_version="$(./gradlew properties --no-daemon -q | awk -F': ' '$1 == "version" { print $2 }')"
tag_version="${GITHUB_REF_NAME#v}"
if [[ -z "$project_version" || "$project_version" != "$tag_version" ]]; then
echo "Tag version '$tag_version' does not match Gradle project version '$project_version'." >&2
exit 1
fi
echo "version=$tag_version" >> "$GITHUB_OUTPUT"

- name: Build and test release
run: ./gradlew clean test jar --no-daemon

- name: Verify and stage release artifacts
id: artifacts
shell: bash
run: |
set -euo pipefail
mapfile -t jars < <(find build/libs -maxdepth 1 -type f -name 'workflowguard-*.jar' -print)
if [[ ${#jars[@]} -ne 1 ]]; then
echo "Expected exactly one WorkflowGuard JAR, found ${#jars[@]}" >&2
exit 1
fi

jar_path="${jars[0]}"
if jar tf "$jar_path" | grep -q '^burp/api/montoya/'; then
echo "The distributable JAR must not bundle Montoya API classes." >&2
exit 1
fi

duplicates="$(jar tf "$jar_path" | sort | uniq -d)"
if [[ -n "$duplicates" ]]; then
echo "Duplicate JAR entries detected:" >&2
echo "$duplicates" >&2
exit 1
fi

mkdir -p dist
cp "$jar_path" dist/
jar_name="$(basename "$jar_path")"
(
cd dist
sha256sum "$jar_name" > "$jar_name.sha256"
sha256sum -c "$jar_name.sha256"
)

notes_path="docs/release-notes-${{ steps.version.outputs.version }}.md"
if [[ ! -f "$notes_path" ]]; then
echo "Missing release notes: $notes_path" >&2
exit 1
fi
echo "notes_path=$notes_path" >> "$GITHUB_OUTPUT"

- name: Upload verified workflow artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: workflowguard-release-${{ steps.version.outputs.version }}
path: dist/
if-no-files-found: error

- name: Publish GitHub release
env:
GH_TOKEN: ${{ github.token }}
NOTES_PATH: ${{ steps.artifacts.outputs.notes_path }}
shell: bash
run: |
set -euo pipefail
if gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1; then
echo "Release $GITHUB_REF_NAME already exists; refusing to overwrite it." >&2
exit 1
fi

gh release create "$GITHUB_REF_NAME" dist/* --verify-tag --title "WorkflowGuard ${{ steps.version.outputs.version }}" --notes-file "$NOTES_PATH"
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Changelog

## Unreleased

### Security

- Update Jackson Databind and the aligned Jackson runtime components to
`2.22.3`, which includes fixes for CVE-2026-91776 and CVE-2026-91777.
- Verify the distributable JAR in CI, reject bundled Montoya API classes and
duplicate entries, and generate a SHA-256 file from the exact artifact.

### Changed

- Add a tag-driven release workflow that requires the tag version to match the
Gradle project version and publishes the same verified JAR/checksum pair.
- Document the `0.3.3` validation-build versus release-asset checksum
discrepancy so historical evidence is not mistaken for the attached binary.
- Refresh the BApp Store readiness review against PortSwigger's
2026-09-22 acceptance criteria.

## 0.3.3 - 2026-07-31

### Security
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ See [Development workflow](docs/development.md),
[BApp readiness matrix](docs/bapp-readiness.md),
[BApp submission text](docs/bapp-submission.md),
[0.3.3 release notes](docs/release-notes-0.3.3.md),
[release integrity process](docs/release-integrity.md),
[Invariant language](docs/invariants.md),
[Workflow files](docs/workflow-files.md), [Architecture](docs/architecture.md),
[Roadmap](docs/roadmap.md), and [Contributing](CONTRIBUTING.md) for the
Expand Down
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ repositories {
dependencies {
compileOnly("net.portswigger.burp.extensions:montoya-api:2026.7")

implementation("com.fasterxml.jackson.core:jackson-databind:2.22.2")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.2")
implementation("com.fasterxml.jackson.core:jackson-databind:2.22.3")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.3")
implementation("com.google.re2j:re2j:1.8")

testImplementation("net.portswigger.burp.extensions:montoya-api:2026.7")
Expand Down
39 changes: 27 additions & 12 deletions docs/bapp-readiness.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# BApp Store publication readiness

Assessment date: 2026-07-31
Assessment date: 2026-09-24

PortSwigger criteria revision checked: 2026-07-28
PortSwigger criteria revision checked: 2026-09-22

## Verdict

WorkflowGuard `0.3.3` satisfies the current technical BApp Store acceptance
criteria. It is ready to be exposed as a public release candidate for
WorkflowGuard `0.3.3` continues to satisfy the current technical BApp Store
acceptance criteria. The source repository is public and suitable for
PortSwigger review.

Submission is intentionally not complete yet. The repository remains private,
and the repository owner must personally accept the legal confirmations in
PortSwigger's extension-portal issue form.
Submission is not recorded as complete in this repository. The repository owner
must personally accept the legal confirmations in PortSwigger's
extension-portal issue form.

## Acceptance-criteria matrix

| # | PortSwigger criterion | WorkflowGuard evidence | Status |
| --- | --- | --- | --- |
| 1 | Unique function | Generates controlled multi-step state mutations and evaluates explicit probes, invariants, and cleanup; this differs from request-matrix, sequence-comparison, and endpoint-organization BApps. | Pass |
| 1 | Unique function | Generates controlled multi-step state mutations and evaluates explicit probes, invariants, and cleanup; this differs from Sequence Comparer, AuthMatrix, Autorize, Auth Analyzer, and API Workflow Manager, which focus on comparison, authorization replay, or endpoint organization rather than mutation of complete stateful workflows with explicit before/after state assertions. | Pass |
| 2 | Clear name and description | `WorkflowGuard`, one-line summary, detailed overview, features, and usage text are prepared in [bapp-submission.md](bapp-submission.md). | Pass |
| 3 | Secure operation | Untrusted request messages are validated before storage and again after rendering. The modeled method, raw method, effective target, Host, scope, request count, origin-bound credentials, extracted values, and state-change confirmation are all enforced. | Pass |
| 4 | All dependencies included | Jackson and RE2/J runtime dependencies, project license, third-party notices, and dependency licenses are embedded in the release JAR. Montoya remains `compileOnly` because Burp provides it. | Pass |
Expand All @@ -44,11 +44,14 @@ PortSwigger's extension-portal issue form.
- The earlier full Community campaign additionally covered authorized
loopback execution, invariant failure, cleanup verification, evidence export,
issue submission behavior, and unload/reload.
- Release JAR: `workflowguard-0.3.3.jar`, **2,852,241 bytes**.
- SHA-256:
- The 2026-07-31 validation build recorded a JAR size of **2,852,241 bytes**
and SHA-256
`8FB9CD29EC79CE5B9489A55F7BCAC321393E7B4426CE63BD84A0B9E5D29955DD`.
- JAR inventory: 1,446 entries, no duplicate entries, no bundled Montoya
classes, and all expected project/dependency notices present.
The binary currently attached to the GitHub `v0.3.3` release is a different
build; see [release integrity](release-integrity.md) before using a checksum
for verification.
- The validated JAR inventory contained 1,446 entries, no duplicate entries,
no bundled Montoya classes, and all expected project/dependency notices.
- Full reachable Git history and publishable files: zero Gitleaks findings.
- OSV query for all bundled runtime components: zero known vulnerabilities on
the assessment date.
Expand All @@ -58,6 +61,18 @@ PortSwigger's extension-portal issue form.
The exact final verification commands and UI observations are recorded in
[community-validation-20260731.md](community-validation-20260731.md).

## Compatibility freshness

- PortSwigger's BApp Store acceptance criteria and submission guidance were
rechecked on 2026-09-24 against documentation updated 2026-09-22.
- The latest Burp Suite Professional / Community release at this review is
`2026.9`, published 2026-09-21.
- Maven Central currently lists Montoya API `2026.7`, which remains the
compile-time API used by WorkflowGuard.
- Direct runtime/UI validation evidence in this repository remains against
Burp Suite Community Edition `2026.7.1`. This document does not claim a
completed direct `2026.9` regression campaign.

## Submission fields

The current PortSwigger submission process requires an accessible GitHub
Expand Down
4 changes: 4 additions & 0 deletions docs/bapp-submission.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ viewer and persistent project files are Professional-only.
invariants.
- AuthMatrix compares requests across users and roles; WorkflowGuard maintains
isolated per-origin actor sessions across complete multi-step flows.
- Autorize and Auth Analyzer automatically replay requests with alternate
credentials and classify authorization outcomes; WorkflowGuard instead
mutates complete captured sequences and evaluates explicit before/after state
invariants, lifecycle ordering, stale values, and verified cleanup.
- API Workflow Manager organizes endpoints; WorkflowGuard models action, probe,
and cleanup roles, resolves dynamic variables, and verifies resulting state.

Expand Down
44 changes: 44 additions & 0 deletions docs/release-integrity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Release integrity and process

This document defines the release process for WorkflowGuard. The goal is to
ensure that the binary published on GitHub, its checksum, the source tag, and
the release notes all refer to the same build.

## Required process

1. Update the Gradle project version and create matching
`docs/release-notes-X.Y.Z.md`.
2. Merge all intended changes to `main` and require a green Build workflow.
3. Create and push the annotated tag `vX.Y.Z` from the exact release commit.
4. Do not create the GitHub release manually before pushing the tag.
5. Let `.github/workflows/release.yml` build, test, verify, checksum, and
publish the release artifacts.
6. Download the published JAR and `.sha256` file and verify them independently
before submitting or updating the BApp Store entry.

The release workflow fails if the tag version does not match the Gradle project
version, if more than one WorkflowGuard JAR is produced, if Montoya API classes
are bundled, if duplicate JAR entries are present, or if release notes are
missing.

## Historical correction for 0.3.3

The validation record created on 2026-07-31 refers to a build with:

- size: 2,852,241 bytes;
- SHA-256:
`8FB9CD29EC79CE5B9489A55F7BCAC321393E7B4426CE63BD84A0B9E5D29955DD`.

The JAR currently attached to the GitHub `v0.3.3` release was uploaded on
2026-08-25 and GitHub reports:

- size: 2,854,635 bytes;
- SHA-256:
`84422c6751fd05574b5e3cdfd20bc64c2a5fd7a6d74be28b0d2d8ccd0df8d043`.

These are different binary builds. The July validation checksum must therefore
not be used to verify the currently attached release asset. The release page
body should be corrected manually to remove the stale size and checksum.

Starting with the next release, the release workflow is the canonical producer
of both the JAR and its checksum.
10 changes: 6 additions & 4 deletions docs/release-notes-0.3.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ Burp Suite workflow mutation extension.
- Gitleaks: zero findings in reachable history and publishable files.
- OSV runtime-dependency query: zero known vulnerabilities on 2026-07-31.

- Artifact: `workflowguard-0.3.3.jar`
- Size: 2,852,241 bytes
- SHA-256:
`8FB9CD29EC79CE5B9489A55F7BCAC321393E7B4426CE63BD84A0B9E5D29955DD`
The validation build used for the 2026-07-31 campaign had size 2,852,241 bytes
and SHA-256
`8FB9CD29EC79CE5B9489A55F7BCAC321393E7B4426CE63BD84A0B9E5D29955DD`.
The binary later attached to the GitHub `v0.3.3` release is not byte-identical
to that validation build. See [release integrity](release-integrity.md) for the
current release-asset digest and the corrected verification guidance.

See the [README](../README.md), [Community validation
report](community-validation-20260731.md), and [BApp readiness
Expand Down
8 changes: 4 additions & 4 deletions gradle.lockfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
# This file is expected to be part of source control.
# To regenerate this file, run: ./gradlew :dependencies --write-locks
com.fasterxml.jackson.core:jackson-annotations:2.22=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-core:2.22.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.22.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson:jackson-bom:2.22.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-core:2.22.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.22.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson:jackson-bom:2.22.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.re2j:re2j:1.8=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.portswigger.burp.extensions:montoya-api:2026.7=compileClasspath,testCompileClasspath,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
Expand Down
Loading