From 276353920da3b77d7ae1a88edc2518ec82865f83 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sat, 30 May 2026 22:26:04 +0300 Subject: [PATCH 1/3] harden: default allow-external-refs to false in the actions CI actions run unattended on pull-request content, including from forks, so the safe default for untrusted input is to not resolve external $refs. All five actions now default allow-external-refs to false: - breaking, changelog, diff, pr-comment: new `allow-external-refs` input (default false), threaded through each entrypoint as --allow-external-refs= so the explicit input is authoritative. - validate: input default flipped true -> false. Users whose specs reference external URLs, or who load split multi-file specs by file path rather than the recommended git-ref form, set allow-external-refs: true to opt back in. Specs loaded via the recommended `origin/main:openapi.yaml` git-ref form (single- and multi-file) are unaffected: relative refs resolve via `git show`, not as external refs. README inputs tables updated. NOTE: effective only on an oasdiff base image that honors the flag on the git-ref load path (oasdiff #974, shipping in v1.18.1). Must land together with the Dockerfile bump to v1.18.1. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 6 +++++- breaking/action.yml | 5 +++++ breaking/entrypoint.sh | 6 ++++++ changelog/action.yml | 5 +++++ changelog/entrypoint.sh | 6 ++++++ diff/action.yml | 5 +++++ diff/entrypoint.sh | 6 ++++++ pr-comment/action.yml | 5 +++++ pr-comment/entrypoint.sh | 6 ++++++ validate/action.yml | 4 ++-- validate/entrypoint.sh | 9 +++++---- 11 files changed, 56 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index bc28e13..16fcc20 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ jobs: | `err-ignore` | `''` | Path to a file containing regex patterns for error-level changes to ignore | file path | | `warn-ignore` | `''` | Path to a file containing regex patterns for warning-level changes to ignore | file path | | `output-to-file` | `''` | Write output to this file path instead of stdout | file path | +| `allow-external-refs` | `false` | Resolve external `$ref`s. Defaults to `false` to prevent SSRF on untrusted pull requests. Set `true` if your spec references external URLs or loads split files by file path | `true`, `false` | ### Generate a changelog @@ -126,6 +127,7 @@ jobs: | `case-insensitive-headers` | `false` | Compare headers case-insensitively | `true`, `false` | | `template` | `''` | Custom Go template for output formatting | Go template string | | `output-to-file` | `''` | Write output to this file path instead of stdout | file path | +| `allow-external-refs` | `false` | Resolve external `$ref`s. Defaults to `false` to prevent SSRF on untrusted pull requests. Set `true` if your spec references external URLs or loads split files by file path | `true`, `false` | ### Generate a diff report @@ -160,6 +162,7 @@ jobs: | `composed` | `false` | Run in composed mode | `true`, `false` | | `flatten-allof` | `false` | Merge allOf subschemas into a single schema before diff | `true`, `false` | | `output-to-file` | `''` | Write output to this file path instead of stdout | file path | +| `allow-external-refs` | `false` | Resolve external `$ref`s. Defaults to `false` to prevent SSRF on untrusted pull requests. Set `true` if your spec references external URLs or loads split files by file path | `true`, `false` | ### Validate a single spec @@ -184,7 +187,7 @@ jobs: |---|---|---|---| | `spec` | — (required) | Path to the OpenAPI spec to validate | file path, URL, git ref | | `fail-on` | `''` | Fail with exit code 1 when a finding is at or above this severity (empty uses the oasdiff default, `ERR`) | `ERR`, `WARN`, `INFO` | -| `allow-external-refs` | `true` | Resolve external `$ref`s; set `false` to prevent SSRF when validating untrusted specs | `true`, `false` | +| `allow-external-refs` | `false` | Resolve external `$ref`s. Defaults to `false` to prevent SSRF on untrusted pull requests. Set `true` if your spec references external URLs | `true`, `false` | For a non-blocking, report-only run, leave `fail-on` and set `continue-on-error: true` on the step. Outputs: `findings` (total), `error_count`, `warning_count`, `info_count`. @@ -292,5 +295,6 @@ Each **Review** link opens a hosted page with a side-by-side spec diff and **App | `include-path-params` | `false` | Include path parameter names in endpoint matching | `true`, `false` | | `exclude-elements` | `''` | Exclude certain kinds of changes from the output | `endpoints`, `request`, `response` (comma-separated) | | `composed` | `false` | Run in composed mode | `true`, `false` | +| `allow-external-refs` | `false` | Resolve external `$ref`s. Defaults to `false` to prevent SSRF on untrusted pull requests. Set `true` if your spec references external URLs or loads split files by file path | `true`, `false` | [Get oasdiff Pro →](https://www.oasdiff.com/pricing) diff --git a/breaking/action.yml b/breaking/action.yml index ef7c00f..14229fb 100644 --- a/breaking/action.yml +++ b/breaking/action.yml @@ -52,6 +52,10 @@ inputs: description: 'Output to a file at the given path' required: false default: '' + allow-external-refs: + description: 'Allow external $refs in the spec; disable to prevent SSRF when processing untrusted specs. Defaults to false (safe for CI on untrusted pull requests).' + required: false + default: 'false' outputs: breaking: description: 'Output summary of API breaking changes, encompassing both warnings and errors' @@ -75,3 +79,4 @@ runs: - ${{ inputs.err-ignore }} - ${{ inputs.warn-ignore }} - ${{ inputs.output-to-file }} + - ${{ inputs.allow-external-refs }} diff --git a/breaking/entrypoint.sh b/breaking/entrypoint.sh index 8033425..95b495b 100755 --- a/breaking/entrypoint.sh +++ b/breaking/entrypoint.sh @@ -20,6 +20,7 @@ readonly flatten_allof="${11}" readonly err_ignore="${12}" readonly warn_ignore="${13}" readonly output_to_file="${14}" +readonly allow_external_refs="${15}" write_output () { local output="$1" @@ -44,6 +45,11 @@ echo "running oasdiff breaking... base: $base, revision: $revision, fail_on: $fa # Build flags to pass in command flags="" +# allow-external-refs defaults to false (safe for CI on untrusted PRs); pass +# whatever the input resolved to so the explicit action input is authoritative. +if [ -n "$allow_external_refs" ]; then + flags="$flags --allow-external-refs=$allow_external_refs" +fi if [ "$include_path_params" = "true" ]; then flags="$flags --include-path-params" fi diff --git a/changelog/action.yml b/changelog/action.yml index 3f14cd9..00a5a7b 100644 --- a/changelog/action.yml +++ b/changelog/action.yml @@ -55,6 +55,10 @@ inputs: description: 'Output level: INFO (default), WARN, or ERR' required: false default: '' + allow-external-refs: + description: 'Allow external $refs in the spec; disable to prevent SSRF when processing untrusted specs. Defaults to false (safe for CI on untrusted pull requests).' + required: false + default: 'false' outputs: changelog: description: 'Output summary of API changelog' @@ -78,4 +82,5 @@ runs: - ${{ inputs.format }} - ${{ inputs.template }} - ${{ inputs.level }} + - ${{ inputs.allow-external-refs }} diff --git a/changelog/entrypoint.sh b/changelog/entrypoint.sh index 1aebe8a..7a5062d 100755 --- a/changelog/entrypoint.sh +++ b/changelog/entrypoint.sh @@ -39,11 +39,17 @@ readonly case_insensitive_headers="${11}" readonly format="${12}" readonly template="${13}" readonly level="${14}" +readonly allow_external_refs="${15}" echo "running oasdiff changelog base: $base, revision: $revision, include_path_params: $include_path_params, exclude_elements: $exclude_elements, filter_extension: $filter_extension, composed: $composed, flatten_allof: $flatten_allof, output_to_file: $output_to_file, prefix_base: $prefix_base, prefix_revision: $prefix_revision, case_insensitive_headers: $case_insensitive_headers, format: $format, template: $template, level: $level" # Build flags to pass in command flags="" +# allow-external-refs defaults to false (safe for CI on untrusted PRs); pass +# whatever the input resolved to so the explicit action input is authoritative. +if [ -n "$allow_external_refs" ]; then + flags="$flags --allow-external-refs=$allow_external_refs" +fi if [ "$include_path_params" = "true" ]; then flags="$flags --include-path-params" fi diff --git a/diff/action.yml b/diff/action.yml index 847b152..750d71f 100644 --- a/diff/action.yml +++ b/diff/action.yml @@ -39,6 +39,10 @@ inputs: description: 'Output to a file at the given path' required: false default: '' + allow-external-refs: + description: 'Allow external $refs in the spec; disable to prevent SSRF when processing untrusted specs. Defaults to false (safe for CI on untrusted pull requests).' + required: false + default: 'false' outputs: diff: description: 'Output summary of API diff' @@ -56,3 +60,4 @@ runs: - ${{ inputs.composed }} - ${{ inputs.flatten-allof }} - ${{ inputs.output-to-file }} + - ${{ inputs.allow-external-refs }} diff --git a/diff/entrypoint.sh b/diff/entrypoint.sh index 186560b..ae9e358 100755 --- a/diff/entrypoint.sh +++ b/diff/entrypoint.sh @@ -35,11 +35,17 @@ readonly filter_extension="$7" readonly composed="$8" readonly flatten_allof="$9" readonly output_to_file="${10}" +readonly allow_external_refs="${11}" echo "running oasdiff diff base: $base, revision: $revision, format: $format, fail_on_diff: $fail_on_diff, include_path_params: $include_path_params, exclude_elements: $exclude_elements, filter_extension: $filter_extension, composed: $composed, flatten_allof: $flatten_allof, output_to_file: $output_to_file" # Build flags to pass in command flags="" +# allow-external-refs defaults to false (safe for CI on untrusted PRs); pass +# whatever the input resolved to so the explicit action input is authoritative. +if [ -n "$allow_external_refs" ]; then + flags="$flags --allow-external-refs=$allow_external_refs" +fi if [ "$format" != "yaml" ]; then flags="$flags --format $format" fi diff --git a/pr-comment/action.yml b/pr-comment/action.yml index e046b59..6833384 100644 --- a/pr-comment/action.yml +++ b/pr-comment/action.yml @@ -30,6 +30,10 @@ inputs: description: 'oasdiff service base URL (override for testing)' required: false default: 'https://api.oasdiff.com' + allow-external-refs: + description: 'Allow external $refs in the spec; disable to prevent SSRF when processing untrusted specs. Defaults to false (safe for CI on untrusted pull requests).' + required: false + default: 'false' runs: using: 'docker' image: 'Dockerfile' @@ -42,3 +46,4 @@ runs: - ${{ inputs.oasdiff-token }} - ${{ inputs.github-token }} - ${{ inputs.service-url }} + - ${{ inputs.allow-external-refs }} diff --git a/pr-comment/entrypoint.sh b/pr-comment/entrypoint.sh index 8ab4340..f27e9a8 100755 --- a/pr-comment/entrypoint.sh +++ b/pr-comment/entrypoint.sh @@ -14,11 +14,17 @@ readonly composed="$5" readonly oasdiff_token="$6" readonly github_token="$7" readonly service_url="${8:-https://api.oasdiff.com}" +readonly allow_external_refs="${9}" echo "running oasdiff pr-comment base: $base, revision: $revision, include_path_params: $include_path_params, exclude_elements: $exclude_elements, composed: $composed" # Build flags flags="" +# allow-external-refs defaults to false (safe for CI on untrusted PRs); pass +# whatever the input resolved to so the explicit action input is authoritative. +if [ -n "$allow_external_refs" ]; then + flags="$flags --allow-external-refs=$allow_external_refs" +fi if [ "$include_path_params" = "true" ]; then flags="$flags --include-path-params" fi diff --git a/validate/action.yml b/validate/action.yml index b358264..60ec87d 100644 --- a/validate/action.yml +++ b/validate/action.yml @@ -9,9 +9,9 @@ inputs: required: false default: '' allow-external-refs: - description: 'Allow external $refs in the spec; disable to prevent SSRF when validating untrusted specs' + description: 'Allow external $refs in the spec; disable to prevent SSRF when validating untrusted specs. Defaults to false (safe for CI on untrusted pull requests).' required: false - default: 'true' + default: 'false' outputs: findings: description: 'Total number of findings reported by validate (0 if the spec is valid)' diff --git a/validate/entrypoint.sh b/validate/entrypoint.sh index 4899134..6a7c11b 100755 --- a/validate/entrypoint.sh +++ b/validate/entrypoint.sh @@ -12,13 +12,14 @@ readonly allow_external_refs="$3" echo "running oasdiff validate... spec: $spec, fail_on: $fail_on, allow_external_refs: $allow_external_refs" -# Build flags. --allow-external-refs defaults to true in oasdiff, so only -# pass it when the input opts out. --fail-on defaults to ERR in oasdiff +# Build flags. The action input allow-external-refs defaults to false (safe for +# CI on untrusted PRs); pass whatever it resolved to so the explicit input is +# authoritative over any oasdiff.yaml value. --fail-on defaults to ERR in oasdiff # (errors fail the build; warnings and info are reported but don't), so only # pass it when the input overrides the threshold. flags="" -if [ "$allow_external_refs" = "false" ]; then - flags="$flags --allow-external-refs=false" +if [ -n "$allow_external_refs" ]; then + flags="$flags --allow-external-refs=$allow_external_refs" fi if [ -n "$fail_on" ]; then flags="$flags --fail-on $fail_on" From eed93f831c0412286bb67a769ab58376dd1dc4ca Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sat, 30 May 2026 22:40:01 +0300 Subject: [PATCH 2/3] actions: emit a recovery hint when external $refs are blocked With allow-external-refs defaulting to false, a spec that resolves an external $ref now fails the step. oasdiff prints the cause to stderr (visible in logs), but that does not explain the new default or name the action input, and the file-path load path emits only kin-openapi's terse "disallowed external reference" with no remedy. Each entrypoint now captures oasdiff's stderr, still surfaces it, and on the external-ref failure signature emits a GitHub ::error:: annotation with the fix: set 'allow-external-refs: true' on the step if the spec is trusted. This turns a post-upgrade red X into a one-glance fix on the PR's Checks tab. Detection matches both the git-ref-path message ("external $ref not allowed") and the file-path message ("disallowed external reference"). No change to the success path or to the authoritative exit code. Co-Authored-By: Claude Opus 4.8 (1M context) --- breaking/entrypoint.sh | 8 +++++++- changelog/entrypoint.sh | 15 +++++++++++++-- diff/entrypoint.sh | 10 ++++++++-- pr-comment/entrypoint.sh | 9 ++++++++- validate/entrypoint.sh | 8 +++++++- 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/breaking/entrypoint.sh b/breaking/entrypoint.sh index 95b495b..648320d 100755 --- a/breaking/entrypoint.sh +++ b/breaking/entrypoint.sh @@ -92,7 +92,13 @@ if [ -n "$fail_on" ]; then fail_on_flag="--fail-on $fail_on" fi exit_code=0 -breaking_changes=$(oasdiff breaking "$base" "$revision" $flags $fail_on_flag) || exit_code=$? +_err=$(mktemp) +breaking_changes=$(oasdiff breaking "$base" "$revision" $flags $fail_on_flag 2>"$_err") || exit_code=$? +[ -s "$_err" ] && cat "$_err" >&2 +if [ "$exit_code" -ne 0 ] && grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then + echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff action step." +fi +rm -f "$_err" # Run 2: render annotations to stdout via --format githubactions so # GitHub parses them onto the PR's "Files changed" tab. Tolerate diff --git a/changelog/entrypoint.sh b/changelog/entrypoint.sh index 7a5062d..91bad4d 100755 --- a/changelog/entrypoint.sh +++ b/changelog/entrypoint.sh @@ -95,11 +95,22 @@ echo "flags: $flags" delimiter=$(cat /proc/sys/kernel/random/uuid | tr -d '-') echo "changelog<<$delimiter" >>"$GITHUB_OUTPUT" +exit_code=0 +_err=$(mktemp) if [ -n "$flags" ]; then - output=$(oasdiff changelog "$base" "$revision" $flags) + output=$(oasdiff changelog "$base" "$revision" $flags 2>"$_err") || exit_code=$? else - output=$(oasdiff changelog "$base" "$revision") + output=$(oasdiff changelog "$base" "$revision" 2>"$_err") || exit_code=$? fi +if [ "$exit_code" -ne 0 ]; then + [ -s "$_err" ] && cat "$_err" >&2 + if grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then + echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff action step." + fi + rm -f "$_err" + exit "$exit_code" +fi +rm -f "$_err" if [ -n "$output" ] && ! echo "$output" | head -n 1 | grep -q "^No "; then write_output "$output" diff --git a/diff/entrypoint.sh b/diff/entrypoint.sh index ae9e358..bcba212 100755 --- a/diff/entrypoint.sh +++ b/diff/entrypoint.sh @@ -81,11 +81,17 @@ echo "diff<<$delimiter" >>"$GITHUB_OUTPUT" # Capture the exit code from oasdiff command while still getting the output exit_code=0 +_err=$(mktemp) if [ -n "$flags" ]; then - output=$(oasdiff diff "$base" "$revision" $flags) || exit_code=$? + output=$(oasdiff diff "$base" "$revision" $flags 2>"$_err") || exit_code=$? else - output=$(oasdiff diff "$base" "$revision") || exit_code=$? + output=$(oasdiff diff "$base" "$revision" 2>"$_err") || exit_code=$? fi +[ -s "$_err" ] && cat "$_err" >&2 +if [ "$exit_code" -ne 0 ] && grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then + echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff action step." +fi +rm -f "$_err" if [ -n "$output" ]; then write_output "$output" diff --git a/pr-comment/entrypoint.sh b/pr-comment/entrypoint.sh index f27e9a8..9d59cac 100755 --- a/pr-comment/entrypoint.sh +++ b/pr-comment/entrypoint.sh @@ -42,11 +42,18 @@ fi # us from collecting the JSON. Real failures (missing file, parse error) # still abort because they leave $changelog empty. oasdiff_exit=0 -changelog=$(oasdiff changelog "$base" "$revision" --format json $flags) || oasdiff_exit=$? +_err=$(mktemp) +changelog=$(oasdiff changelog "$base" "$revision" --format json $flags 2>"$_err") || oasdiff_exit=$? if [ "$oasdiff_exit" -ne 0 ] && [ -z "$changelog" ]; then + [ -s "$_err" ] && cat "$_err" >&2 + if grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then + echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff action step." + fi + rm -f "$_err" echo "ERROR: oasdiff exited $oasdiff_exit with no output" >&2 exit $oasdiff_exit fi +rm -f "$_err" # If no changes, use empty array if [ -z "$changelog" ] || [ "$changelog" = "null" ] || [ "$changelog" = "[]" ]; then diff --git a/validate/entrypoint.sh b/validate/entrypoint.sh index 6a7c11b..1453d6c 100755 --- a/validate/entrypoint.sh +++ b/validate/entrypoint.sh @@ -32,7 +32,13 @@ echo "flags: $flags" # threshold, 0 otherwise). Tolerate non-zero so we can still set the outputs # below; the exit code is reapplied at the end. exit_code=0 -oasdiff validate $flags --format githubactions "$spec" || exit_code=$? +_err=$(mktemp) +oasdiff validate $flags --format githubactions "$spec" 2>"$_err" || exit_code=$? +[ -s "$_err" ] && cat "$_err" >&2 +if [ "$exit_code" -ne 0 ] && grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then + echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff validate step." +fi +rm -f "$_err" # Run 2: text format, captured for the finding count. Tolerate non-zero # exit (the authoritative decision is already captured above). From b75db7de6a25c9114901ec8157fdc1b809e91a37 Mon Sep 17 00:00:00 2001 From: Reuven Harrison Date: Sat, 30 May 2026 23:19:54 +0300 Subject: [PATCH 3/3] actions: detect disallowed external $ref by exit code 123, not message text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit oasdiff returns a dedicated exit code (123) for a spec that resolves an external $ref under --allow-external-refs=false. Key the recovery hint off that code instead of grepping oasdiff's stderr for "external $ref not allowed" / "disallowed external reference" — text is brittle (kin-openapi owns the file-path wording; messages can change), an exit code is a stable contract. Requires the v1.18.1 base image (oasdiff exit-code change). The raw error is still surfaced for every failure; this only gates the action-specific remedy. Co-Authored-By: Claude Opus 4.8 (1M context) --- breaking/entrypoint.sh | 4 +++- changelog/entrypoint.sh | 4 +++- diff/entrypoint.sh | 4 +++- pr-comment/entrypoint.sh | 4 +++- validate/entrypoint.sh | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/breaking/entrypoint.sh b/breaking/entrypoint.sh index 648320d..a1c4bc8 100755 --- a/breaking/entrypoint.sh +++ b/breaking/entrypoint.sh @@ -95,7 +95,9 @@ exit_code=0 _err=$(mktemp) breaking_changes=$(oasdiff breaking "$base" "$revision" $flags $fail_on_flag 2>"$_err") || exit_code=$? [ -s "$_err" ] && cat "$_err" >&2 -if [ "$exit_code" -ne 0 ] && grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then +# Exit code 123 = oasdiff refused a disallowed external $ref (stable contract, +# not message text). Surface the action-specific remedy. +if [ "$exit_code" -eq 123 ]; then echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff action step." fi rm -f "$_err" diff --git a/changelog/entrypoint.sh b/changelog/entrypoint.sh index 91bad4d..e4318f2 100755 --- a/changelog/entrypoint.sh +++ b/changelog/entrypoint.sh @@ -104,7 +104,9 @@ else fi if [ "$exit_code" -ne 0 ]; then [ -s "$_err" ] && cat "$_err" >&2 - if grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then + # Exit code 123 = oasdiff refused a disallowed external $ref (stable + # contract, not message text). Surface the action-specific remedy. + if [ "$exit_code" -eq 123 ]; then echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff action step." fi rm -f "$_err" diff --git a/diff/entrypoint.sh b/diff/entrypoint.sh index bcba212..3e32d15 100755 --- a/diff/entrypoint.sh +++ b/diff/entrypoint.sh @@ -88,7 +88,9 @@ else output=$(oasdiff diff "$base" "$revision" 2>"$_err") || exit_code=$? fi [ -s "$_err" ] && cat "$_err" >&2 -if [ "$exit_code" -ne 0 ] && grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then +# Exit code 123 = oasdiff refused a disallowed external $ref (stable contract, +# not message text). Surface the action-specific remedy. +if [ "$exit_code" -eq 123 ]; then echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff action step." fi rm -f "$_err" diff --git a/pr-comment/entrypoint.sh b/pr-comment/entrypoint.sh index 9d59cac..cafd5c0 100755 --- a/pr-comment/entrypoint.sh +++ b/pr-comment/entrypoint.sh @@ -46,7 +46,9 @@ _err=$(mktemp) changelog=$(oasdiff changelog "$base" "$revision" --format json $flags 2>"$_err") || oasdiff_exit=$? if [ "$oasdiff_exit" -ne 0 ] && [ -z "$changelog" ]; then [ -s "$_err" ] && cat "$_err" >&2 - if grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then + # Exit code 123 = oasdiff refused a disallowed external $ref (stable + # contract, not message text). Surface the action-specific remedy. + if [ "$oasdiff_exit" -eq 123 ]; then echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff action step." fi rm -f "$_err" diff --git a/validate/entrypoint.sh b/validate/entrypoint.sh index 1453d6c..6db87f1 100755 --- a/validate/entrypoint.sh +++ b/validate/entrypoint.sh @@ -35,7 +35,9 @@ exit_code=0 _err=$(mktemp) oasdiff validate $flags --format githubactions "$spec" 2>"$_err" || exit_code=$? [ -s "$_err" ] && cat "$_err" >&2 -if [ "$exit_code" -ne 0 ] && grep -qiE 'external \$ref not allowed|disallowed external reference' "$_err"; then +# Exit code 123 = oasdiff refused a disallowed external $ref (stable contract, +# not message text). Surface the action-specific remedy. +if [ "$exit_code" -eq 123 ]; then echo "::error::oasdiff: this spec resolves external \$refs, which are disabled by default to prevent SSRF on untrusted pull requests. If the spec is trusted, set 'allow-external-refs: true' on the oasdiff validate step." fi rm -f "$_err"