From 6c69fcbaaa1adf67ddd92b4723a5999398f6e578 Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Thu, 5 Nov 2026 20:19:49 +0800 Subject: [PATCH] Inject Slack Actions secrets and verify live client credentials --- .gitea/workflows/check.yml | 47 +++++++++++++++++++++++++++++++++++++ .gitea/workflows/deploy.yml | 2 ++ deploy/release.sh | 12 +++++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/.gitea/workflows/check.yml b/.gitea/workflows/check.yml index 588e2e8..7c005a3 100644 --- a/.gitea/workflows/check.yml +++ b/.gitea/workflows/check.yml @@ -17,6 +17,53 @@ jobs: test -z "$(gofmt -l cmd internal)" go test -mod=readonly ./... go build -mod=readonly -o bin/foundry ./cmd/foundry + - name: Verify configured Slack client credentials + if: gitea.event_name == 'push' + env: + SLACK_CLIENT_ID: ${{ secrets.SLACK_CLIENT_ID }} + SLACK_CLIENT_SECRET: ${{ secrets.SLACK_CLIENT_SECRET }} + run: | + python3 - <<'PYSLACK' + import json, os, secrets, sys, urllib.parse, urllib.request + client = os.environ.get("SLACK_CLIENT_ID", "") + secret = os.environ.get("SLACK_CLIENT_SECRET", "") + if not client and not secret: + print("Slack client verification skipped because credentials are not configured") + sys.exit(0) + if not client or not secret: + sys.exit("Both Slack client secrets must be configured") + class NoRedirect(urllib.request.HTTPRedirectHandler): + def redirect_request(self, *args, **kwargs): + return None + opener = urllib.request.build_opener(NoRedirect) + code = "foundry-invalid-preflight-" + secrets.token_hex(16) + def probe(password): + body = urllib.parse.urlencode({ + "client_id": client, "client_secret": password, + "code": code, "grant_type": "authorization_code", + "redirect_uri": "https://api.foundry.entroia.com/auth/slack/callback" + }).encode() + request = urllib.request.Request( + "https://slack.com/api/openid.connect.token", data=body, + headers={"Content-Type": "application/x-www-form-urlencoded"}) + with opener.open(request, timeout=20) as response: + result = json.load(response) + return result.get("error", "") + try: + actual = probe(secret) + control = probe(secrets.token_hex(32)) + except Exception as error: + sys.exit("Slack preflight request failed (" + type(error).__name__ + ")") + if actual in ("invalid_code", "invalid_grant") and control in ("bad_client_secret", "invalid_client"): + print("Slack client credentials accepted; invalid-secret negative control rejected") + print("A real user authorization is still required to verify the complete login") + else: + known = {"invalid_client_id", "bad_client_secret", "invalid_client", "invalid_code", + "invalid_grant", "bad_redirect_uri", "accesslimited", "ratelimited"} + print("Configured credential result:", actual if actual in known else "unclassified") + print("Negative control result:", control if control in known else "unclassified") + sys.exit("Slack client preflight could not verify the configured credentials") + PYSLACK - name: Verify schema migration in an isolated database run: bash deploy/check-schema.sh - name: Smoke test HTTP routes diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index f2d5c54..928e4f3 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -36,6 +36,8 @@ jobs: env: GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }} GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }} + SLACK_CLIENT_ID: ${{ secrets.SLACK_CLIENT_ID }} + SLACK_CLIENT_SECRET: ${{ secrets.SLACK_CLIENT_SECRET }} FOUNDRY_PROJECTS: ${{ vars.FOUNDRY_PROJECTS }} FOUNDRY_ONBOARDING: ${{ vars.FOUNDRY_ONBOARDING }} run: bash deploy/release.sh bin/foundry diff --git a/deploy/release.sh b/deploy/release.sh index 39433be..22f6be7 100644 --- a/deploy/release.sh +++ b/deploy/release.sh @@ -50,7 +50,17 @@ if [[ -s "$foundry/mail.env" ]]; then mail_env=(--env-file "$foundry/mail.env") fi slack_env=() -if [[ -s "$foundry/slack.env" ]]; then +if [[ -n "${SLACK_CLIENT_ID:-}" || -n "${SLACK_CLIENT_SECRET:-}" ]]; then + for name in SLACK_CLIENT_ID SLACK_CLIENT_SECRET; do + value=${!name-} + if [[ -z "$value" || "$value" == *$'\n'* || "$value" == *$'\r'* ]]; then + printf 'Missing or invalid %s\n' "$name" >&2 + exit 1 + fi + done + export SLACK_CLIENT_ID SLACK_CLIENT_SECRET + slack_env=(-e SLACK_CLIENT_ID -e SLACK_CLIENT_SECRET) +elif [[ -s "$foundry/slack.env" ]]; then slack_env=(--env-file "$foundry/slack.env") fi codex_mounts=()