diff --git a/services/jenkins/deployment.yaml b/services/jenkins/deployment.yaml index 06791318..d6bb8f58 100644 --- a/services/jenkins/deployment.yaml +++ b/services/jenkins/deployment.yaml @@ -48,7 +48,11 @@ spec: TITAN_IAC_WEBHOOK_TOKEN={{ .Data.data.titan_iac_quality_gate }} GIT_NOTIFY_TOKEN_BSTEIN_DEV_HOME={{ .Data.data.git_notify_bstein_dev_home }} {{ end }} - bstein.dev/restarted-at: "2026-02-02T15:10:33Z" + {{ with secret "kv/data/atlas/jenkins/ariadne-api" }} + ARIADNE_JENKINS_API_USER={{ .Data.data.username }} + ARIADNE_JENKINS_API_TOKEN={{ .Data.data.token }} + {{ end }} + bstein.dev/restarted-at: "2026-04-13T05:20:00Z" spec: serviceAccountName: jenkins nodeSelector: diff --git a/services/jenkins/kustomization.yaml b/services/jenkins/kustomization.yaml index 10fe911d..3737f86a 100644 --- a/services/jenkins/kustomization.yaml +++ b/services/jenkins/kustomization.yaml @@ -22,6 +22,7 @@ configMapGenerator: - name: jenkins-init-scripts namespace: jenkins files: + - ariadne-api-user.groovy=scripts/ariadne-api-user.groovy - git-notify-token.groovy=scripts/git-notify-token.groovy - theme.groovy=scripts/theme.groovy options: diff --git a/services/jenkins/scripts/ariadne-api-user.groovy b/services/jenkins/scripts/ariadne-api-user.groovy new file mode 100644 index 00000000..aeec25cb --- /dev/null +++ b/services/jenkins/scripts/ariadne-api-user.groovy @@ -0,0 +1,85 @@ +import hudson.model.User +import jenkins.security.ApiTokenProperty + +def userId = (System.getenv("ARIADNE_JENKINS_API_USER") ?: "").trim() +def tokenValue = (System.getenv("ARIADNE_JENKINS_API_TOKEN") ?: "").trim() +def tokenName = "ariadne-weather" +def tokenFile = new File("/var/jenkins_home/secrets/ariadne-api-token") +def userFile = new File("/var/jenkins_home/secrets/ariadne-api-user") + +if (!userId || !tokenValue) { + println("Ariadne API user bootstrap skipped: missing ARIADNE_JENKINS_API_USER or ARIADNE_JENKINS_API_TOKEN") + return +} + +def user = User.getById(userId, true) +if (user == null) { + println("Ariadne API user bootstrap failed: unable to resolve user ${userId}") + return +} + +if (!user.getFullName() || user.getFullName().trim() == userId) { + user.setFullName("Ariadne Metrics") +} + +def prop = user.getProperty(ApiTokenProperty.class) +if (prop == null) { + prop = new ApiTokenProperty() + user.addProperty(prop) +} + +if (!prop.matchesPassword(tokenValue)) { + def store = prop.getTokenStore() + def existing = store.getTokenListSortedByName().find { token -> + try { + token.getName() == tokenName + } catch (Throwable ignored) { + false + } + } + + if (existing != null) { + try { + store.revokeToken(existing.getUuid()) + } catch (Throwable ignored) { + try { + store.revokeToken(existing.uuid) + } catch (Throwable ignoredAgain) { + println("Ariadne API user bootstrap warning: failed to revoke existing token ${tokenName}") + } + } + } + + boolean configured = false + try { + store.addFixedNewToken(tokenName, tokenValue) + configured = true + } catch (Throwable ignored) { + // Fallback for older token-store variants. + } + + if (!configured) { + def generated = store.generateNewToken(tokenName) + if (generated?.plainValue) { + tokenValue = generated.plainValue + } + println("Ariadne API user bootstrap warning: addFixedNewToken unavailable, generated replacement token") + } +} + +tokenFile.parentFile?.mkdirs() +tokenFile.text = tokenValue + "\n" +tokenFile.setReadable(false, false) +tokenFile.setReadable(true, true) +tokenFile.setWritable(false, false) +tokenFile.setWritable(true, true) + +userFile.parentFile?.mkdirs() +userFile.text = userId + "\n" +userFile.setReadable(false, false) +userFile.setReadable(true, true) +userFile.setWritable(false, false) +userFile.setWritable(true, true) + +user.save() +println("Ariadne API user bootstrap complete for ${userId}") diff --git a/services/maintenance/ariadne-deployment.yaml b/services/maintenance/ariadne-deployment.yaml index 9c830761..44a8456f 100644 --- a/services/maintenance/ariadne-deployment.yaml +++ b/services/maintenance/ariadne-deployment.yaml @@ -18,13 +18,15 @@ spec: prometheus.io/scrape: "true" prometheus.io/port: "8080" prometheus.io/path: "/metrics" - maintenance.bstein.dev/restart-rev: "20260207-2" + maintenance.bstein.dev/restart-rev: "20260413-jenkins-api" vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "maintenance" vault.hashicorp.com/agent-inject-secret-ariadne-env.sh: "kv/data/atlas/maintenance/ariadne-db" vault.hashicorp.com/agent-inject-template-ariadne-env.sh: | {{ with secret "kv/data/atlas/maintenance/ariadne-db" }} export ARIADNE_DATABASE_URL="{{ .Data.data.database_url }}" + export JENKINS_API_USER="{{ .Data.data.jenkins_api_user }}" + export JENKINS_API_TOKEN="{{ .Data.data.jenkins_api_token }}" {{ end }} {{ with secret "kv/data/atlas/portal/atlas-portal-db" }} export PORTAL_DATABASE_URL="{{ .Data.data.PORTAL_DATABASE_URL }}"