102 lines
5.2 KiB
YAML
102 lines
5.2 KiB
YAML
name: Foundry Go checks
|
|
on: [push, pull_request]
|
|
|
|
jobs:
|
|
check:
|
|
runs-on: ces-control
|
|
# Cold toolchain installation can exceed ten minutes on the existing runner.
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-go@v5
|
|
with:
|
|
go-version-file: go.mod
|
|
cache: false
|
|
- name: Check formatting, test and build
|
|
run: |
|
|
set -eu
|
|
test -z "$(gofmt -l cmd internal)"
|
|
go test -mod=readonly ./...
|
|
go build -mod=readonly -o bin/foundry ./cmd/foundry
|
|
- name: Check Slack OAuth configuration and endpoint
|
|
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")
|
|
elif actual in ("invalid_code", "invalid_grant") and control in ("invalid_code", "invalid_grant"):
|
|
print("Both Slack Actions secrets are available and the OAuth endpoint is reachable")
|
|
print("Slack rejected the placeholder code before validating the client secret")
|
|
print("Client-secret validity requires a real user authorization; this is not a complete login test")
|
|
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: Fetch pinned headless HTTP integration client
|
|
env:
|
|
HEADLESS_CLIENT_REVISION: c07f8fbd8268d6e71f163ba664bca37af9fb0bae
|
|
run: |
|
|
set -eu
|
|
mkdir -p .headless-client
|
|
curl --fail --silent --show-error --location \
|
|
"https://gitea.entroia.com/Zayden-Jung/Endoleap/archive/$HEADLESS_CLIENT_REVISION.tar.gz" \
|
|
| tar -xz --strip-components=1 -C .headless-client
|
|
test -f .headless-client/tests/headless/foundry.integration.mjs
|
|
printf 'Pinned Endoleap client: %s\n' "$HEADLESS_CLIENT_REVISION"
|
|
- name: Verify schema migration and real headless HTTP client in an isolated database
|
|
run: HEADLESS_CLIENT_SOURCE="$PWD/.headless-client" bash deploy/check-schema.sh
|
|
- name: Smoke test HTTP routes
|
|
env:
|
|
PUBLIC_ORIGIN: https://api.example.com
|
|
DATABASE_URL: postgres://foundry:fixture@127.0.0.1:5432/foundry
|
|
FOUNDRY_RESEARCH_DATABASE_URL: ''
|
|
GOOGLE_CLIENT_ID: fixture
|
|
GOOGLE_CLIENT_SECRET: fixture
|
|
FOUNDRY_PROJECTS: '{"notes":"http://localhost:3000/auth/callback"}'
|
|
PORT: '18080'
|
|
run: |
|
|
set -eu
|
|
./bin/foundry &
|
|
server_pid=$!
|
|
trap 'kill "$server_pid" 2>/dev/null || true' EXIT
|
|
curl --silent --show-error --fail --retry 5 --retry-connrefused http://127.0.0.1:18080/healthz
|
|
status=$(curl --silent --show-error -o /dev/null -w '%{http_code}' http://127.0.0.1:18080/projects/notes/auth/me)
|
|
test "$status" = 401
|