8181 echo "python_deps_changed=$(has_file '^(pyproject\.toml|uv\.lock)$')"
8282 echo "fixture_npm_changed=$(has_file '^tests/e2e/fixtures/simple-npm/')"
8383 echo "fixture_pypi_changed=$(has_file '^tests/e2e/fixtures/simple-pypi/')"
84- echo "dockerfile_changed=$(has_file '^Dockerfile$')"
84+ echo "dockerfile_changed=$(has_file '^( Dockerfile|scripts/docker-entrypoint\.sh) $')"
8585 echo "workflow_or_action_changed=$(has_file '^\.github/workflows/|^\.github/actions/|^\.github/dependabot\.yml$')"
8686 } >> "$GITHUB_OUTPUT"
8787
@@ -562,7 +562,18 @@ jobs:
562562 dockerfile-smoke :
563563 needs : inspect
564564 if : needs.inspect.outputs.dockerfile_changed == 'true'
565- runs-on : ubuntu-latest
565+ # Build every architecture the release publishes, each on a native runner,
566+ # so an arm64-only break shows up here rather than in release.yml.
567+ strategy :
568+ fail-fast : false
569+ matrix :
570+ include :
571+ - arch : amd64
572+ runner : ubuntu-24.04
573+ - arch : arm64
574+ runner : ubuntu-24.04-arm
575+ name : dockerfile-smoke (${{ matrix.arch }})
576+ runs-on : ${{ matrix.runner }}
566577 timeout-minutes : 20
567578 steps :
568579 - uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -576,6 +587,71 @@ jobs:
576587 --build-arg USE_LOCAL_INSTALL=true
577588 -t socket-python-cli:dependabot-smoke .
578589
590+ - name : Check the tools in the image
591+ run : |
592+ docker run --rm --entrypoint sh socket-python-cli:dependabot-smoke -c '
593+ set -eu
594+ echo "node $(node -v), npm $(npm -v), yarn $(yarn -v)"
595+ socket --version
596+ socketcli --version
597+ '
598+
599+ # The eMudhra test hosts serve certificates from the compromised
600+ # intermediates. Require the specific rejection, not just any failure, so
601+ # a DNS or network error cannot pass as "rejected".
602+ - name : Check TLS clients reject the compromised eMudhra intermediates
603+ run : |
604+ docker run --rm --entrypoint sh socket-python-cli:dependabot-smoke -c '
605+ set -u
606+ status=0
607+ for host in dv-g3b-emudhra.we-have-a-problem.com dv-g3b-aaa-emudhra.we-have-a-problem.com; do
608+ code=0
609+ curl -sS -m 30 -o /dev/null "https://$host/" 2>/dev/null || code=$?
610+ if [ "$code" = 60 ]; then
611+ echo "curl rejects $host"
612+ else
613+ echo "::error::curl on $host exited $code, expected 60 (certificate verification failed)"
614+ status=1
615+ fi
616+ result=$(node -e "
617+ const req = require(\"https\").get(process.argv[1], { timeout: 30000 }, (res) => {
618+ console.log(\"ACCEPTED\"); process.exit(0);
619+ });
620+ req.on(\"timeout\", () => { console.log(\"TIMEOUT\"); process.exit(0); });
621+ req.on(\"error\", (e) => { console.log(e.code || e.message); process.exit(0); });
622+ " "https://$host/")
623+ case "$result" in
624+ CERT_REVOKED|UNABLE_TO_GET_ISSUER_CERT_LOCALLY|UNABLE_TO_VERIFY_LEAF_SIGNATURE) echo "node rejects $host ($result)" ;;
625+ *) echo "::error::node on $host: $result"; status=1 ;;
626+ esac
627+ result=$(python -c "
628+ import sys, requests
629+ try:
630+ requests.get(sys.argv[1], timeout=30)
631+ print(\"ACCEPTED\")
632+ except requests.exceptions.SSLError:
633+ print(\"SSLError\")
634+ except Exception as e:
635+ print(type(e).__name__)
636+ " "https://$host/")
637+ if [ "$result" = SSLError ]; then
638+ echo "python rejects $host"
639+ else
640+ echo "::error::python requests on $host: $result"
641+ status=1
642+ fi
643+ done
644+ for url in https://api.socket.dev/v0/ https://registry.npmjs.org/ https://pypi.org/simple/; do
645+ if curl -sS -m 30 -o /dev/null "$url"; then
646+ echo "curl connects to $url"
647+ else
648+ echo "::error::curl cannot connect to $url"
649+ status=1
650+ fi
651+ done
652+ exit $status
653+ '
654+
579655 workflow-notice :
580656 needs : inspect
581657 if : needs.inspect.outputs.workflow_or_action_changed == 'true'
0 commit comments