Files
cc-ci/nix/modules/bridge.nix
autonomic-bot 8262912015
All checks were successful
continuous-integration/drone Build is passing
feat(1d): enroll hedgedoc in bridge POLL_REPOS (DG6 unconfigured-recipe target)
hedgedoc mirrored to recipe-maintainers/hedgedoc with probe PR #1; add it to the bridge poll list so
!testme triggers the full generic suite (no cc-ci/repo-local overlay -> pure generic). Rebuild pending.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 01:47:29 +01:00

121 lines
5.0 KiB
Nix

# Comment-bridge (§4.1): the `!testme` webhook receiver. Packaged as a Nix-built OCI image
# (no Docker Hub pull) and run as a swarm service on `proxy`, routed by traefik at
# ci.commoninternet.net/hook. Deployed by an idempotent-reconcile oneshot (same pattern as
# proxy/drone). Secrets come from sops (/run/secrets) → swarm secrets the container mounts.
{ pkgs, ... }:
let
# bridge.py placed at /app/bridge.py inside the image.
bridgeApp = pkgs.runCommand "cc-ci-bridge-app" { } ''
mkdir -p $out/app
cp ${../../bridge/bridge.py} $out/app/bridge.py
'';
# Content-derived tag so `docker stack deploy` rolls the service whenever bridge.py changes
# (a fixed `:latest` + unchanged stack spec does NOT roll — swarm sees no change).
imageTag = builtins.substring 0 12 (builtins.hashString "sha256"
(builtins.readFile ../../bridge/bridge.py));
image = pkgs.dockerTools.buildLayeredImage {
name = "cc-ci-bridge";
tag = imageTag;
contents = [ pkgs.python3 pkgs.cacert bridgeApp ];
config = {
Cmd = [ "${pkgs.python3}/bin/python3" "/app/bridge.py" ];
Env = [ "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ];
ExposedPorts = { "8080/tcp" = { }; };
};
};
stack = pkgs.writeText "cc-ci-bridge-stack.yml" ''
version: "3.8"
services:
app:
image: cc-ci-bridge:${imageTag}
environment:
- GITEA_API=https://git.autonomic.zone/api/v1
- DRONE_URL=https://drone.ci.commoninternet.net
- CI_REPO=recipe-maintainers/cc-ci
- BRIDGE_LISTEN=0.0.0.0:8080
# Polling is PRIMARY (outbound, read-only, always on); the /hook webhook is an optional
# admin-registered push optimization deduped against the poller (§4.1). Enrollment = add
# the repo to POLL_REPOS (csv) + ensure tests/<recipe>/ exists.
- POLL_INTERVAL=30
- POLL_REPOS=recipe-maintainers/cc-ci,recipe-maintainers/custom-html,recipe-maintainers/keycloak,recipe-maintainers/cryptpad,recipe-maintainers/matrix-synapse,recipe-maintainers/lasuite-docs,recipe-maintainers/n8n,recipe-maintainers/hedgedoc
- HMAC_FILE=/run/secrets/webhook_hmac
- DRONE_TOKEN_FILE=/run/secrets/drone_token
- GITEA_TOKEN_FILE=/run/secrets/gitea_token
secrets:
- webhook_hmac
- drone_token
- gitea_token
networks:
- proxy
deploy:
replicas: 1
restart_policy:
condition: any
labels:
- "traefik.enable=true"
- "traefik.http.services.ccci-bridge.loadbalancer.server.port=8080"
- "traefik.http.routers.ccci-bridge.rule=Host(`ci.commoninternet.net`) && PathPrefix(`/hook`)"
- "traefik.http.routers.ccci-bridge.entrypoints=web-secure"
- "traefik.http.routers.ccci-bridge.tls=true"
networks:
proxy:
external: true
secrets:
webhook_hmac:
external: true
name: cc_ci_bridge_webhook_hmac_v1
drone_token:
external: true
name: cc_ci_bridge_drone_token_v1
gitea_token:
external: true
name: cc_ci_bridge_gitea_token_v1
'';
reconcile = pkgs.writeShellApplication {
name = "cc-ci-reconcile-bridge";
runtimeInputs = with pkgs; [ docker coreutils ];
text = ''
for s in webhook_hmac drone_token gitea_token; do
if [ ! -r "/run/secrets/bridge_$s" ]; then
echo "FATAL: /run/secrets/bridge_$s missing (rebuild ordering?)" >&2
exit 1
fi
done
# Load the Nix-built image into the local docker (idempotent; layers cached).
docker load -i ${image}
# Materialise swarm secrets from sops (immutable; create once at v1).
ensure_secret() {
docker secret inspect "$2" >/dev/null 2>&1 || docker secret create "$2" "$1" >/dev/null
}
ensure_secret /run/secrets/bridge_webhook_hmac cc_ci_bridge_webhook_hmac_v1
ensure_secret /run/secrets/bridge_drone_token cc_ci_bridge_drone_token_v1
ensure_secret /run/secrets/bridge_gitea_token cc_ci_bridge_gitea_token_v1
docker stack deploy --detach=true -c ${stack} ccci-bridge
'';
};
in
{
systemd.services.deploy-bridge = {
description = "Reconcile the cc-ci comment-bridge (!testme webhook) swarm service";
# Serialized after deploy-drone (chain proxy→drone→bridge→dashboard→backupbot): on a FRESH host the
# abra-driven reconcilers otherwise run concurrently against an uninitialised ~/.abra and race on
# catalogue/recipe init, leaving units failed after a blank-VM rebuild. Ordering-only `after` fixes it.
after = [ "deploy-drone.service" "deploy-proxy.service" "swarm-init.service" "docker.service" "network-online.target" ];
requires = [ "swarm-init.service" "docker.service" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${reconcile}/bin/cc-ci-reconcile-bridge";
};
};
}