diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml index 5ca7edba1..351ccf1cc 100644 --- a/.github/workflows/sync-upstream.yml +++ b/.github/workflows/sync-upstream.yml @@ -22,12 +22,16 @@ jobs: name: sync runs-on: ubuntu-latest timeout-minutes: 15 + # master is protected (pull request, "lists" required) and only a deploy key may bypass it. + # The key is a secret of the "sync" environment, which runs for master only. + environment: + name: sync permissions: - contents: write + contents: read issues: write steps: # No credentials in the checkout: the sync and the checks process upstream's data, and only - # the commit step, below, is handed the token it pushes with. + # the commit step, below, is handed the key it pushes with. - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false @@ -54,7 +58,7 @@ jobs: - name: Commit to master if: steps.sync.outputs.rc == '0' env: - GH_TOKEN: ${{ github.token }} + DEPLOY_KEY: ${{ secrets.SYNC_DEPLOY_KEY }} run: | set -euo pipefail if [ -z "$(git status --porcelain -- all.json address.json known.json all meta pezkuwi/upstream.json)" ]; then @@ -65,8 +69,14 @@ jobs: git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git add -A -- all.json address.json known.json all meta pezkuwi/upstream.json git commit -q -m "chore(lists): sync with polkadot-js/phishing" -m "$(grep -E '^(SYNC |unblocked: )' sync.out)" - gh auth setup-git - git push origin HEAD:master + install -d -m 700 ~/.ssh + umask 077 + printf '%s\n' "$DEPLOY_KEY" > ~/.ssh/sync_deploy + # GitHub's own host keys, committed in pezkuwi/github_host_keys: nothing learned at run time. + sed 's|^|github.com |' pezkuwi/github_host_keys > ~/.ssh/known_hosts + GIT_SSH_COMMAND="ssh -i $HOME/.ssh/sync_deploy -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes" \ + git push git@github.com:pezkuwichain/phishing.git HEAD:master + rm -f ~/.ssh/sync_deploy - name: Ask a person if: steps.sync.outputs.rc != '0' diff --git a/pezkuwi/github_host_keys b/pezkuwi/github_host_keys new file mode 100644 index 000000000..f4c560e0e --- /dev/null +++ b/pezkuwi/github_host_keys @@ -0,0 +1,3 @@ +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= diff --git a/pezkuwi/host/phishing-publish.sh b/pezkuwi/host/phishing-publish.sh index 63b26cd32..44d2bce5d 100644 --- a/pezkuwi/host/phishing-publish.sh +++ b/pezkuwi/host/phishing-publish.sh @@ -136,7 +136,9 @@ for domain in protected: print(f"checked: {len(deny)} blocked sites, {sum(len(v) for v in address.values())} scam addresses") PY -rsync -a --checksum --delete --delay-updates --chown=root:root --exclude index.html "$stage/" "$WEB_ROOT/" +# Modes are set, not copied: the stage is a mktemp directory, 0700, and copying its mode made the +# web root unreadable to nginx. Every list answered 403 until it was put back (2026-09-13). +rsync -a --checksum --delete --delay-updates --chown=root:root --chmod=D755,F644 --exclude index.html "$stage/" "$WEB_ROOT/" printf '%s\n' "$new" >"$STATE_DIR/published.new" mv -f "$STATE_DIR/published.new" "$STATE_DIR/published" echo "published ${new:0:12}" diff --git a/pezkuwi/host/test-publish.sh b/pezkuwi/host/test-publish.sh index 482ae8aa4..6a2b7d900 100644 --- a/pezkuwi/host/test-publish.sh +++ b/pezkuwi/host/test-publish.sh @@ -75,6 +75,9 @@ check "all.json is master's" "$(sha256sum <"$LISTS/all.json")" "$(sha256sum <"$S check "a shard is master's" "$(sha256sum <"$LISTS/all/com/all.json")" "$(sha256sum <"$SB/www/all/com/all.json")" check "the stray all/all.json is gone" no "$([ -e "$SB/www/all/all.json" ] && echo yes || echo no)" check "index.html untouched" "$INDEX" "$(sha256sum "$SB/www/index.html")" +# nginx reads as another user: a web root or list it cannot read answers 403. +check "the web root and its directories are 755" 0 "$(find "$SB/www" -type d ! -perm 755 | wc -l)" +check "the lists are 644" 0 "$(find "$SB/www" -type f ! -name index.html ! -perm 644 | wc -l)" check "the published commit is recorded" "$(git -C "$SB/work" rev-parse HEAD)" "$(cat "$SB/state/published")" check "nothing new: exit" 0 "$(publish)" check "nothing new: silent" "" "$(cat "$SB/out")"