diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52bfbf2..4773944 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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" @@ -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 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..63b00c7 --- /dev/null +++ b/.github/workflows/release.yml @@ -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" diff --git a/CHANGELOG.md b/CHANGELOG.md index 7170e95..77bff49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index edd8fb7..d39b677 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/build.gradle.kts b/build.gradle.kts index 5f7a5c6..d30677c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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") diff --git a/docs/bapp-readiness.md b/docs/bapp-readiness.md index 34e0931..92fcc5a 100644 --- a/docs/bapp-readiness.md +++ b/docs/bapp-readiness.md @@ -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 | @@ -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. @@ -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 diff --git a/docs/bapp-submission.md b/docs/bapp-submission.md index aeae130..e0377d5 100644 --- a/docs/bapp-submission.md +++ b/docs/bapp-submission.md @@ -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. diff --git a/docs/release-integrity.md b/docs/release-integrity.md new file mode 100644 index 0000000..fb31f76 --- /dev/null +++ b/docs/release-integrity.md @@ -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. diff --git a/docs/release-notes-0.3.3.md b/docs/release-notes-0.3.3.md index cfcc765..2f0b3e7 100644 --- a/docs/release-notes-0.3.3.md +++ b/docs/release-notes-0.3.3.md @@ -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 diff --git a/gradle.lockfile b/gradle.lockfile index 6e46141..61fb059 100644 --- a/gradle.lockfile +++ b/gradle.lockfile @@ -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