diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfdb8b7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.sh text eol=lf diff --git a/.github/workflows/stormdns-boundary.yml b/.github/workflows/stormdns-boundary.yml new file mode 100644 index 0000000..89ed6e0 --- /dev/null +++ b/.github/workflows/stormdns-boundary.yml @@ -0,0 +1,50 @@ +name: StormDNS Boundary + +on: + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + - unlabeled + +permissions: + contents: read + pull-requests: read + +jobs: + upstream-guard: + name: Guard upstream engine changes + runs-on: ubuntu-latest + + steps: + - name: Checkout WhiteDNS + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: false + + - name: Check StormDNS upstream boundary + env: + HAS_UPSTREAM_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'allow-stormdns-upstream') }} + run: | + set -euo pipefail + base_ref="${{ github.event.pull_request.base.sha }}" + head_ref="${{ github.event.pull_request.head.sha }}" + + set +e + scripts/check-stormdns-boundary.sh "${base_ref}" "${head_ref}" + guard_status="$?" + set -e + + if [[ "${guard_status}" == "0" ]]; then + exit 0 + fi + + if [[ "${guard_status}" == "1" && "${HAS_UPSTREAM_LABEL}" == "true" ]]; then + echo "StormDNS upstream changes are intentionally labeled." + exit 0 + fi + + exit "${guard_status}" diff --git a/docs/STORMDNS_UPSTREAM_POLICY.md b/docs/STORMDNS_UPSTREAM_POLICY.md new file mode 100644 index 0000000..c4517cb --- /dev/null +++ b/docs/STORMDNS_UPSTREAM_POLICY.md @@ -0,0 +1,52 @@ +# StormDNS Upstream Policy + +WhiteDNS treats `third_party/StormDNS` as a black-box upstream engine. + +The Android app must integrate with StormDNS only through stable runtime boundaries: + +- The packaged StormDNS executable. +- CLI flags passed to that executable. +- Generated TOML configuration files. +- Generated resolver files. +- stdout/stderr telemetry emitted by the process. +- Process exit codes. +- Version and capability detection from the executable. +- Files written by StormDNS under the WhiteDNS-owned working directory. + +## Disallowed Coupling + +WhiteDNS app features must not depend on: + +- StormDNS internal Go packages. +- Private StormDNS source layout. +- Unexported Go symbols or package structure. +- Parsing upstream Go source files for app behavior. +- Editing upstream code to satisfy Android app feature needs. +- Runtime assumptions that require knowing StormDNS internals beyond documented executable behavior. + +Build tooling may know where the upstream client command lives so it can compile the executable. App runtime code must not. + +## Allowed Upstream Changes + +Changes under `third_party/StormDNS` or `.gitmodules` are allowed only when they are intentional upstream maintenance, such as: + +- Updating the pinned submodule commit. +- Syncing a reviewed upstream fix. +- Refreshing native binaries from a documented upstream commit. + +Any pull request that changes `third_party/StormDNS` or `.gitmodules` must include the label: + +`allow-stormdns-upstream` + +Without that label, CI fails before review to prevent accidental local edits to the upstream engine. + +## Review Checklist + +For any pull request touching StormDNS integration: + +- Confirm app code interacts through the executable boundary only. +- Confirm generated TOML and resolver files are owned by WhiteDNS and live under app-controlled runtime directories. +- Confirm telemetry parsing is tolerant of unknown or changed output. +- Confirm optional behavior is gated by executable version/capability detection when needed. +- Confirm no Android app code imports, parses, or depends on StormDNS Go internals. +- Confirm `third_party/StormDNS` and `.gitmodules` changes are either absent or intentionally labeled and explained. diff --git a/scripts/check-stormdns-boundary.sh b/scripts/check-stormdns-boundary.sh new file mode 100755 index 0000000..05e8f0f --- /dev/null +++ b/scripts/check-stormdns-boundary.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +set -euo pipefail + +base_ref="${1:-origin/main}" +head_ref="${2:-HEAD}" + +if ! git rev-parse --verify "${base_ref}" >/dev/null 2>&1; then + echo "Base ref '${base_ref}' is not available." >&2 + exit 2 +fi + +if ! git rev-parse --verify "${head_ref}" >/dev/null 2>&1; then + echo "Head ref '${head_ref}' is not available." >&2 + exit 2 +fi + +changed_files="$( + git diff --name-only "${base_ref}...${head_ref}" -- 'third_party/StormDNS' '.gitmodules' +)" + +if [[ -z "${changed_files}" ]]; then + echo "No StormDNS upstream changes detected." + exit 0 +fi + +echo "StormDNS upstream changes detected:" >&2 +echo "${changed_files}" >&2 +echo >&2 +echo "WhiteDNS treats third_party/StormDNS as a black-box upstream engine." >&2 +echo "Add the 'allow-stormdns-upstream' pull request label only when these changes are intentional upstream maintenance." >&2 +exit 1