2 Commits

Author SHA1 Message Date
Sharang Parnerkar 3fa0e26bd1 ci(portal): sign orca webhook POST with HMAC-SHA256
ci / shared (pull_request) Successful in 13s
ci / test (pull_request) Successful in 10m17s
ci / e2e (pull_request) Has been skipped
ci / image (pull_request) Has been skipped
When `orca webhooks add` registers a webhook it generates a signing
secret by default; orca then requires X-Hub-Signature-256 on inbound
POSTs (the public master at :6880 means anyone could otherwise fire
a deploy by crafting the JSON body).

Adds the signing step using the standard github-shaped header. The
secret is consumed from a new Gitea Actions secret ORCA_WEBHOOK_SECRET
on this repo — value provided out-of-band from the master.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 12:18:12 +02:00
Sharang Parnerkar 8fc4dc09c9 ci(portal): retarget image build to registry.meghsakha.com + orca webhook
ci / shared (pull_request) Successful in 14s
ci / test (pull_request) Successful in 10m17s
ci / e2e (pull_request) Has been skipped
ci / image (pull_request) Has been skipped
The previous CI pushed to registry.breakpilot.com (the future prod
registry that doesn't exist yet) and tried to call `orca apply`, a
CLI shape this orca version doesn't ship. Repointing to the live
infrastructure:

- registry: registry.meghsakha.com
- image path: breakpilot/portal (sibling of breakpilot/compliance-*)
- tags: :latest (for the webhook-driven deploy) + :sha-<sha> (traceability)
- redeploy: POST github-style payload to the orca webhook on the master,
  matching the pattern documented in orca-infra/WEBHOOKS.md

The webhook must be registered once on the master:
  orca webhooks add --repo platform/portal \
                    --service breakpilot-portal --branch main

CI also needs REGISTRY_USER + REGISTRY_PASS set on this Gitea repo's
Actions secrets — same htpasswd-backed creds the master uses today.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 12:12:44 +02:00
+1 -14
View File
@@ -11,20 +11,7 @@ export type HostMatch =
| { kind: "unknown" };
// Longest-first so `stage.breakpilot.com` is matched before `breakpilot.com`.
// Built-ins cover dev (localhost) + the canonical breakpilot.com targets.
// PORTAL_APEX_HOSTS is a comma-separated env override for per-environment
// hosts (e.g. portal-dev.meghsakha.com while breakpilot.com isn't registered).
const APEX_HOSTS = (() => {
const base = ["stage.breakpilot.com", "breakpilot.com", "localhost"];
const extra = (process.env.PORTAL_APEX_HOSTS ?? "")
.split(",")
.map((h) => h.trim().toLowerCase())
.filter(Boolean);
// Longest-first to keep the suffix-strip loop correct.
return Array.from(new Set([...extra, ...base])).sort(
(a, b) => b.length - a.length,
);
})();
const APEX_HOSTS = ["stage.breakpilot.com", "breakpilot.com", "localhost"];
const APEX_SET = new Set(APEX_HOSTS);
export function parseHost(host: string | null | undefined): HostMatch {