recruiter-responder: public /cb ingress for Telegram URL-button callbacks
- Add ingress_factory module (auth=none, HMAC + expiry are the gate); ingress_path=["/cb"] only — /api stays internal, /healthz cluster. dns_type=proxied. anti_ai_scraping=false. - Drop setup_tls_secret module — Kyverno ClusterPolicy `sync-tls-secret` auto-clones the wildcard cert into every namespace. - Bump image_tag to 7383b426 (callback endpoints + SMTP STARTTLS hostname relax). - Wire CALLBACK_BASE_URL=https://recruiter-responder.viktorbarzin.me. - Drop git-crypt-encrypted wildcard cert files into stacks/recruiter-responder/secrets/. Allowlist privkey.pem in a new .gitleaksignore — git-crypt encrypts at rest but the working-tree copy is plaintext, so gitleaks can't tell. Smoke-tested end-to-end 2026-05-15 23:45: synthetic email -> Telegram with ✅/❌ buttons -> ✅ tapped via curl -> 'Sent' HTML page -> thread.status=sent, decision row recorded with decided_via=telegram_button, outbound message threaded correctly. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
77010b769a
commit
aa6e9b0242
5 changed files with 40 additions and 1 deletions
4
.gitleaksignore
Normal file
4
.gitleaksignore
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# git-crypt encrypts these at rest; the working-tree plaintext is local-only.
|
||||||
|
# gitleaks scans the staged working-tree copy and can't see that they're
|
||||||
|
# encrypted on disk in git, so allowlist by fingerprint.
|
||||||
|
stacks/recruiter-responder/secrets/privkey.pem:private-key:1
|
||||||
|
|
@ -6,6 +6,11 @@ variable "image_tag" {
|
||||||
|
|
||||||
variable "postgresql_host" { type = string }
|
variable "postgresql_host" { type = string }
|
||||||
|
|
||||||
|
variable "tls_secret_name" {
|
||||||
|
type = string
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
locals {
|
locals {
|
||||||
namespace = "recruiter-responder"
|
namespace = "recruiter-responder"
|
||||||
image = "forgejo.viktorbarzin.me/viktor/recruiter-responder:${var.image_tag}"
|
image = "forgejo.viktorbarzin.me/viktor/recruiter-responder:${var.image_tag}"
|
||||||
|
|
@ -243,6 +248,12 @@ resource "kubernetes_deployment" "recruiter_responder" {
|
||||||
value = "http://claude-agent-service.claude-agent.svc.cluster.local:8080"
|
value = "http://claude-agent-service.claude-agent.svc.cluster.local:8080"
|
||||||
}
|
}
|
||||||
# Telegram bot (no URL env needed — token in secret)
|
# Telegram bot (no URL env needed — token in secret)
|
||||||
|
# Public callback base URL for inline-keyboard URL buttons.
|
||||||
|
# Must match the ingress host below (proxied via Cloudflare).
|
||||||
|
env {
|
||||||
|
name = "CALLBACK_BASE_URL"
|
||||||
|
value = "https://recruiter-responder.viktorbarzin.me"
|
||||||
|
}
|
||||||
|
|
||||||
readiness_probe {
|
readiness_probe {
|
||||||
http_get {
|
http_get {
|
||||||
|
|
@ -298,3 +309,27 @@ resource "kubernetes_service" "recruiter_responder" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Kyverno ClusterPolicy `sync-tls-secret` auto-clones the wildcard TLS
|
||||||
|
# secret into every namespace, so we don't need a setup_tls_secret module.
|
||||||
|
|
||||||
|
# Public ingress for the /cb/* callback endpoints driven by Telegram URL
|
||||||
|
# buttons. /api/* and /healthz stay internal — they're routed via cluster
|
||||||
|
# DNS from the OpenClaw plugin / kubelet probes respectively.
|
||||||
|
#
|
||||||
|
# auth = "none": the /cb endpoints are gated by HMAC-signed query params
|
||||||
|
# (sig + exp) generated from WEBHOOK_BEARER_TOKEN. Authentik would force
|
||||||
|
# a login flow before the GET could fire and break the one-tap flow.
|
||||||
|
module "ingress" {
|
||||||
|
source = "../../modules/kubernetes/ingress_factory"
|
||||||
|
# auth = "none": HMAC + expiry gate the /cb endpoints — Authentik would
|
||||||
|
# force a login dance and break Telegram's one-tap UX. See callback_links.py.
|
||||||
|
auth = "none"
|
||||||
|
anti_ai_scraping = false
|
||||||
|
dns_type = "proxied"
|
||||||
|
namespace = kubernetes_namespace.recruiter_responder.metadata[0].name
|
||||||
|
name = "recruiter-responder"
|
||||||
|
port = 8080
|
||||||
|
ingress_path = ["/cb"]
|
||||||
|
tls_secret_name = var.tls_secret_name
|
||||||
|
}
|
||||||
|
|
|
||||||
BIN
stacks/recruiter-responder/secrets/fullchain.pem
Normal file
BIN
stacks/recruiter-responder/secrets/fullchain.pem
Normal file
Binary file not shown.
BIN
stacks/recruiter-responder/secrets/privkey.pem
Normal file
BIN
stacks/recruiter-responder/secrets/privkey.pem
Normal file
Binary file not shown.
|
|
@ -19,5 +19,5 @@ dependency "external-secrets" {
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
# Override per-deploy in CI / commit.
|
# Override per-deploy in CI / commit.
|
||||||
image_tag = "0500c3d3"
|
image_tag = "7383b426"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue