Inject Slack Actions secrets and verify live client credentials
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
+11
-1
@@ -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=()
|
||||
|
||||
Reference in New Issue
Block a user