Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .conformance-catalog-ref
Original file line number Diff line number Diff line change
@@ -1 +1 @@
b4c758a7dac698d7fcacd32dafcd4bb2f5dbddaf
583a6d92412543ea352251c88f15f2c5a39d2593
361 changes: 361 additions & 0 deletions .github/scripts/conformance-case-body-drift.sh

Large diffs are not rendered by default.

629 changes: 629 additions & 0 deletions .github/scripts/conformance-case-body-drift.test.sh

Large diffs are not rendered by default.

70 changes: 70 additions & 0 deletions .github/scripts/conformance-registered-case-ids.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash
#
# Print the conformance case ids THIS SDK registers, one per line.
#
# This is the repo-specific half of the case-body drift check: the id source
# depends on how this repo's harness records registrations, so it lives here and
# conformance-case-body-drift.sh stays generic.
#
# For this repo the ids come out of conformance-report.json, which the
# conformance suite writes from TestMain. That is the harness's own record of
# what registered, so it cannot disagree with what the suite actually did — the
# reason for reading the report rather than grepping Case(t, "...") calls out of
# the test sources, which would be a second, weaker id extractor that reports
# what it matched and stays silent about what it missed.
#
# The report lists one entry per CATALOG case, so presence in it is not
# registration. `nodeid` is: Case() sets it at registration time, and the
# placeholder entries the report synthesizes for uncovered catalog cases leave
# it empty. Reading `nodeid` rather than `status` matters — a registered case
# whose test failed or skipped is still registered, and still needs its body
# watched, but its status is not "passed".
#
# Requires the suite to have run, so the report on disk belongs to this commit.
#
# Inputs (environment):
# CONFORMANCE_REPORT path to conformance-report.json
# (default: $GITHUB_WORKSPACE/conformance-report.json)
#
# Exit status:
# 0 ids printed on stdout
# 1 the report is missing, unreadable, or holds no registered case

set -euo pipefail

REPORT="${CONFORMANCE_REPORT:-${GITHUB_WORKSPACE:-.}/conformance-report.json}"

fail() {
echo "::error::$1" >&2
exit 1
}

if ! command -v jq > /dev/null 2>&1; then
fail "registered case ids: jq is not available, so the conformance report cannot be read."
fi

if [[ ! -f "$REPORT" ]]; then
fail "registered case ids: '$REPORT' does not exist. The conformance suite writes it from TestMain, so either the suite did not run or it failed before the report was written."
fi

if ! jq -e . "$REPORT" > /dev/null 2>&1; then
fail "registered case ids: '$REPORT' is not valid JSON."
fi

if ! jq -e '(.cases | type) == "array" and (.cases | length) > 0' "$REPORT" > /dev/null 2>&1; then
fail "registered case ids: '$REPORT' has no non-empty .cases array."
fi

# An entry with a case_id that is not a string, or empty, would silently drop
# out of the filter below and take a real registration with it.
if ! jq -e 'all(.cases[]; (.case_id | type) == "string" and (.case_id | length) > 0)' "$REPORT" > /dev/null 2>&1; then
fail "registered case ids: '$REPORT' holds a case entry with a missing or non-string case_id."
fi

ids="$(jq -r '.cases[] | select((.nodeid // "") != "") | .case_id' "$REPORT")"

if [[ -z "$ids" ]]; then
fail "registered case ids: '$REPORT' records no case with a nodeid, so no conformance marker registered. Any check restricted to this list would be vacuously green."
fi

printf '%s\n' "$ids"
64 changes: 50 additions & 14 deletions .github/scripts/fetch-conformance-catalog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,59 @@
#
# Fetch the conformance catalog at the revision this repo pins.
#
# The catalog lives in github.com/AuthPlane/conformance and is updated
# independently of this repo, so cloning its default branch would let a catalog
# Generic: nothing here is specific to one workflow or one caller's layout.
# Every workflow in this repo that needs the pinned catalog runs this one
# script, so a guard tightened here is tightened for all of them.
#
# The catalog lives in github.com/AuthPlane/conformance — a public repo, updated
# independently of this one — so cloning its default branch would let a catalog
# change turn an unrelated PR red here. The ref is pinned instead, single-sourced
# from the tracked .conformance-catalog-ref at the repo root — bump it there when
# from the tracked .conformance-catalog-ref at the repo root: bump it when
# adopting new catalog cases, together with the coverage for them, so a catalog
# change can never break CI on its own.
#
# This script exists because the read/guard/fetch sequence is needed by more than
# one workflow (ci.yml and release.yml). Keeping it inline in both meant the
# guard could be tightened in one and not the other; the pin was single-sourced
# but the logic reading it was not.
#
# Clones into $RUNNER_TEMP — outside $GITHUB_WORKSPACE — so the catalog stays out
# of the working tree: it must never trip `go list ./...` or a coverage glob, and
# `git add -A` in the release commit must never stage it as a gitlink.
# of the working tree: it must never be picked up by this repo's own build, test
# or coverage tooling, and `git add -A` in the release commit must never stage it
# as an embedded gitlink.
#
# Plain git over HTTPS is enough: the repo is public and read-only here, so there
# is no token to plumb and no third-party action surface to SHA-pin.
#
# Requires: GITHUB_WORKSPACE, RUNNER_TEMP.
#
# Optional: CONFORMANCE_CATALOG_DEST overrides the clone directory. A caller that
# needs the pinned catalog and the catalog tip side by side in the same job
# cannot let both land on the default path. Every other caller leaves it unset
# and gets $RUNNER_TEMP/conformance. It must be an absolute path outside
# $GITHUB_WORKSPACE: the out-of-tree rule above holds for every destination, not
# only the default, and is enforced below rather than left to the caller.

set -euo pipefail

: "${GITHUB_WORKSPACE:?GITHUB_WORKSPACE must be set}"
: "${RUNNER_TEMP:?RUNNER_TEMP must be set}"

REF_FILE="$GITHUB_WORKSPACE/.conformance-catalog-ref"
DEST="$RUNNER_TEMP/conformance"
DEST="${CONFORMANCE_CATALOG_DEST:-$RUNNER_TEMP/conformance}"
CATALOG_REPO="https://github.com/AuthPlane/conformance.git"
CATALOG_FILE="oauth-sdk-conformance-catalog.yaml"

# Hold the destination to the out-of-tree rule, override or not. A relative path
# resolves against the caller's working directory — $GITHUB_WORKSPACE for a
# `run:` step — and an in-workspace path puts the clone in the tree directly; a
# destination equal to the workspace root would have the checkout below replace
# this repo's own working tree with the catalog. The trailing slash is stripped
# so a destination under a $GITHUB_WORKSPACE written with one is still caught.
WORKSPACE="${GITHUB_WORKSPACE%/}"
if [[ "$DEST" != /* ]]; then
echo "::error::The conformance catalog destination must be an absolute path, got '$DEST'"
exit 1
fi
if [[ "$DEST" == "$WORKSPACE" || "$DEST" == "$WORKSPACE"/* ]]; then
echo "::error::The conformance catalog destination must be outside \$GITHUB_WORKSPACE ($WORKSPACE), got '$DEST'"
exit 1
fi

if [[ ! -f "$REF_FILE" ]]; then
echo "::error::$REF_FILE is missing; the conformance catalog revision is unpinned"
Expand All @@ -36,8 +63,8 @@ fi

CONFORMANCE_CATALOG_REF="$(tr -d '[:space:]' < "$REF_FILE")"

# Guard against un-pinning: the ref must be a full commit SHA, not a branch or
# tag name, either of which would silently track a moving target.
# Guard against un-pinning BEFORE the fetch: the ref must be a full commit SHA,
# not a branch or tag name, either of which would silently track a moving target.
if ! grep -Eq '^[0-9a-f]{40}$' <<< "$CONFORMANCE_CATALOG_REF"; then
echo "::error::.conformance-catalog-ref must be a 40-hex commit SHA, got '$CONFORMANCE_CATALOG_REF'"
exit 1
Expand All @@ -50,4 +77,13 @@ if ! git -C "$DEST" fetch --depth=1 "$CATALOG_REPO" "$CONFORMANCE_CATALOG_REF";
fi
git -C "$DEST" checkout -q FETCH_HEAD

echo "Conformance catalog checked out at $CONFORMANCE_CATALOG_REF"
# The alignment assertion hard-fails when CONFORMANCE_CATALOG_PATH points at a
# missing file, but it reports that as a harness problem rather than drift. Fail
# here instead, where the cause is unambiguous: the fetch succeeded and the
# catalog still is not where every caller expects it.
if [[ ! -f "$DEST/$CATALOG_FILE" ]]; then
echo "::error::$CATALOG_FILE is not in the catalog at $CONFORMANCE_CATALOG_REF; the fetch succeeded but produced no catalog in $DEST"
exit 1
fi

echo "Conformance catalog checked out at $CONFORMANCE_CATALOG_REF in $DEST"
Loading
Loading