Author SHA1 Message Date
JMR-devandClaude Opus 5.5 f0de95ee4e README: day-to-day make targets need ADC
The Makefile derives PROJECT and ZONE from `pulumi config get`, which
reads the stack from the GCS backend and so needs Application Default
Credentials. Without them the lookup fails silently and every gcloud
command runs with `--project=`. The passphrase is not needed for
plaintext config values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:42:48 +07:00
JMR-devandClaude Opus 5.5 f362d26ed7 Let the VM list DNS zones so Caddy can present DNS-01 challenges
With DNS resolution fixed, issuance failed at the challenge:

  presenting for challenge: adding temporary record for zone
  "gitea.jasonmross.dev.": googleapi: Error 403: Forbidden

Testing with the VM service account's own token: managedZones/main and
its rrsets return 200, but managedZones (list) returns 403. The
googleclouddns plugin resolves the domain to a zone by listing the
project's managed zones, and listing is a project-level permission that
the zone-scoped dns.admin binding cannot grant.

Grant roles/dns.reader on the project. It adds read access only, in a
project that holds this single zone; every write stays zone-scoped. A
custom role with just dns.managedZones.list was the alternative, but
managing it would need iam.roleAdmin on the cb-infra Pulumi runner,
which widens a far more powerful identity to narrow a read-only one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:37:12 +07:00
JMR-devandClaude Opus 5.5 be965b58cf runbook: note that Caddy's certificates live on the boot disk
The caddy-data volume is a podman named volume, so it sits under
/var/lib/containers on the boot disk rather than the separately managed
data disk. An instance replacement re-registers the ACME account and
re-issues, and enough of those in a week hits Let's Encrypt's
duplicate-certificate limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:21:56 +07:00
JMR-devandClaude Opus 5.5 b4fad783e4 nftables: let containers reach aardvark-dns
Caddy could not obtain a certificate on first boot: every request to
acme-v02.api.letsencrypt.org timed out. Containers could reach
1.1.1.1:443 by address but resolved no names at all.

Container DNS goes to aardvark-dns on the bridge gateway (10.89.10.1:53).
That traffic terminates on the host, so it takes the input hook, not
forward. Netavark accepts it in its own table, but gitea_filter's input
chain has policy drop, and a packet must be accepted by every base chain
on the hook. Our drop won.

gitea_filter now accepts tcp/udp 53 from the podman subnet to its
gateway. Both come from instance metadata, so the ruleset is rendered
with envsubst, as the fail2ban jail already is. It is not interface-based
because netavark's bridge name (podman1) is not pinned.

setup_nftables also validates the rendered file before installing it.
Previously it installed first and validated second, so a ruleset that
failed to parse stayed in /etc/sysconfig and would fail nftables.service
on the next boot, leaving the host with no gitea_filter table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:09:49 +07:00
JMR-devandClaude Opus 5.5 9adfe9fc84 image build: enable BuildKit
The first image build failed in build-gitea:

  the --chmod option requires BuildKit

Both Dockerfiles declare `# syntax=docker/dockerfile:1` and use
`COPY --chmod`, but gcr.io/cloud-builders/docker runs the legacy builder
unless DOCKER_BUILDKIT=1 is set. The image ships the buildx plugin, so
setting it on the two build steps is all that is needed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:01:26 +07:00
JMR-devandClaude Opus 5.5 529dc87373 Give manual image builds a source bucket cb-image can read
The first `make build` failed before any step ran:

  INVALID_ARGUMENT: could not resolve source: cb-image@... does not
  have storage.objects.get access to ... gitea-496920_cloudbuild/source/...

`gcloud builds submit` uploads the source tarball to <project>_cloudbuild
and the build, running as the user-specified cb-image@, must read it
back. Nothing grants that. Binding on that bucket is not an option: gcloud
creates it on the first submit, after `pulumi up` has already run.
Project-wide objectViewer would also open the backup, config and state
buckets.

Pulumi now owns <project>-gitea-build-source, readable by cb-image@ and
nothing else, with a 7-day delete rule since each tarball is read once.
`make build` stages there via --gcs-source-staging-dir. Triggered builds
fetch source through the GitHub connection and are unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:50:58 +07:00
JMR-devandClaude Opus 5.5 da62266766 make build: supply SHORT_SHA to manual builds
image.yaml tags each image :$SHORT_SHA as its audit trail and rollback
target. Cloud Build populates SHORT_SHA only for triggered builds; for
`gcloud builds submit` it substitutes an empty string, so the tag becomes
`<image>:` and docker build fails with an invalid reference format. That
is the very first build in the README's setup sequence.

Pass the current commit's short hash explicitly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:49:25 +07:00
JMR-devandClaude Opus 5.5 0acf3b7863 Configure the prod stack for gitea-496920
Fills in the values scripts/bootstrap.sh and the existing project
provide: the project id, the Cloud DNS zone resource name (main, holding
gitea.jasonmross.dev), and the cb-infra Pulumi runner account.

encryptionsalt is from `pulumi stack init` with the passphrase already in
Secret Manager (pulumi-config-passphrase), so Cloud Build's infra trigger
can open the stack with the same key.

githubAppInstallationId stays "0" for now: GitHubConfigured() is then
false and the Cloud Build triggers are skipped until the GitHub App is
installed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:41:58 +07:00
JMR-devandClaude Opus 5.5 f0e7a3b66f Keep the ACME contact email in Secret Manager
gitea:acmeEmail sat in Pulumi.prod.yaml, which this public repository
publishes, and was then copied into instance metadata. It now lives in a
gitea-acme-email secret instead, read by the VM when it renders the
Caddyfile.

- scripts/bootstrap.sh creates the secret empty and prints how to set
  it, the same as github-pat: the address is chosen, not generated.
- Pulumi grants the VM secretAccessor on it and nothing more. It is kept
  out of secrets.Names, whose members also get secretVersionAdder and are
  mapped to `gitea generate secret` by vm/bootstrap.sh.
- The gitea:acmeEmail config key and the acme-email metadata entry are
  gone.
- vm/bootstrap.sh renders the whole `email` directive. If the secret is
  unreadable it renders a comment instead and warns: Caddy still issues
  certificates under an account with no contact address, whereas an
  empty `email` would fail to parse and leave nothing serving TLS. Same
  directive-or-comment pattern as CADDY_PUBLISH_PORTS and CADDY_SYSCTL.

README setup gains the secret step, plus two that were missing: ADC
login (Pulumi's GCS backend and provider do not use the gcloud login),
and exporting PULUMI_CONFIG_PASSPHRASE from Secret Manager before
`stack init`. Without the latter, init prompts for a new passphrase and
the stack is encrypted with a key Cloud Build's infra trigger never sees.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:39:44 +07:00
JMR-devandClaude Opus 5.5 367b188eae Build the Pulumi binary before running Pulumi
Pulumi.yaml sets runtime.options.binary to ./gitea-infra, which tells the
Go language host to execute that file instead of compiling the program.
Nothing produced it: `make check` ran `go build ./...`, which discards
output when building multiple packages, and the infra Cloud Build step
went straight to `pulumi up`. Both local preview/up and the first infra
trigger run would fail before planning anything.

`make check` (and therefore preview/up) now builds it with -o, and the
infra pipeline builds it at the top of the pulumi step. `go vet ./...`
still type-checks every package.

Also corrects the Makefile's ZONE fallback from <region>-a to <region>-b.
It applies whenever `pulumi config get` cannot read the stack, and
us-east1 has no -a zone, so make ssh/build would target a zone that does
not exist. -b matches the default in infra/pkg/config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:29:46 +07:00
JMR-devandClaude Opus 5.5 d05908133c Fix Dependabot alerts: upgrade grpc and otel, pin go1.26.9
Eight open Dependabot alerts, all transitive through the Pulumi SDK:

  grpc  < 1.82.2 / <= 1.83.0   (#3, #4 high; #5 medium) -> v1.83.2
  otel/sdk, otlptrace, otlptracegrpc  <= 1.44.0  (#6-8)  -> v1.45.0
  otel/sdk/log, otlplog/otlploggrpc   <  0.21.0  (#9-10) -> v0.21.0

This supersedes Dependabot PR #1, which bumps grpc only and predates the
otel alerts.

otel/log v0.21 changed its API, so the otelslog bridge has to move with
it: v0.18.0 no longer compiles against it. v0.20.1 is the release built
for that otel line.

govulncheck then reported ten reachable standard-library and x/net
vulnerabilities disclosed since the last pin (net/http HTTP/2 and CONNECT
handling, net/textproto, crypto/tls ECH, os on Windows), all fixed in
go1.26.9 and golang.org/x/net v0.60.0. Raising the toolchain floor is the
same remedy as before; x/net v0.60.0 requires go 1.26, which lifts the
go directive from 1.25.11 to 1.26.0.

The Pulumi SDK and pulumi-gcp direct dependencies are deliberately left
where they are, so this does not also change provider behaviour ahead of
the first deploy.

govulncheck now reports no reachable vulnerabilities. GO-2026-5932
(x/crypto/openpgp, no fix available, not called) remains, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 14:29:06 +07:00
19 changed files with 274 additions and 122 deletions
+14 -3
View File
@@ -3,7 +3,8 @@
PROJECT ?= $(shell cd infra && pulumi config get gcp:project 2>/dev/null) PROJECT ?= $(shell cd infra && pulumi config get gcp:project 2>/dev/null)
REGION ?= $(shell cd infra && pulumi config get gcp:region 2>/dev/null || echo us-east1) REGION ?= $(shell cd infra && pulumi config get gcp:region 2>/dev/null || echo us-east1)
ZONE ?= $(shell cd infra && pulumi config get gitea:zone 2>/dev/null || echo $(REGION)-a) # -b, matching the default in infra/pkg/config: us-east1 has no -a zone.
ZONE ?= $(shell cd infra && pulumi config get gitea:zone 2>/dev/null || echo $(REGION)-b)
VM ?= gitea-vm VM ?= gitea-vm
.PHONY: help .PHONY: help
@@ -19,9 +20,11 @@ bootstrap: ## One-time project setup (run before the first `make up`)
fmt: ## Format Go sources fmt: ## Format Go sources
cd infra && gofmt -w . cd infra && gofmt -w .
# -o gitea-infra: Pulumi.yaml points the go runtime at this prebuilt binary, so
# Pulumi runs it rather than compiling. Without it preview/up fail outright.
.PHONY: check .PHONY: check
check: ## Build and vet the Pulumi program, and syntax-check the shell scripts check: ## Build and vet the Pulumi program, and syntax-check the shell scripts
cd infra && go build ./... && go vet ./... cd infra && go build -o gitea-infra . && go vet ./...
bash -n vm/bootstrap.sh scripts/bootstrap.sh bash -n vm/bootstrap.sh scripts/bootstrap.sh
@command -v shellcheck >/dev/null && shellcheck -S warning vm/bootstrap.sh scripts/bootstrap.sh || echo "shellcheck not installed -- skipped" @command -v shellcheck >/dev/null && shellcheck -S warning vm/bootstrap.sh scripts/bootstrap.sh || echo "shellcheck not installed -- skipped"
@@ -41,12 +44,20 @@ up: check ## Apply the infrastructure
# to cb-image@, not to whatever default Cloud Build account this project # to cb-image@, not to whatever default Cloud Build account this project
# happens to have -- and on newer projects the legacy default does not exist. # happens to have -- and on newer projects the legacy default does not exist.
# Without this the images push fine and the rollout step fails. # Without this the images push fine and the rollout step fails.
# --gcs-source-staging-dir: running as cb-image@, the build must be able to read
# the uploaded source. Pulumi grants that on this bucket only; the default
# <project>_cloudbuild bucket is unreadable to it and the build fails at
# "could not resolve source".
# SHORT_SHA: Cloud Build fills it in only for triggered builds. For `builds
# submit` it is empty, and image.yaml's `--tag <image>:$SHORT_SHA` becomes an
# invalid reference that fails the build.
.PHONY: build .PHONY: build
build: ## Build and roll out the container images via Cloud Build build: ## Build and roll out the container images via Cloud Build
gcloud builds submit --config cloudbuild/image.yaml --project $(PROJECT) \ gcloud builds submit --config cloudbuild/image.yaml --project $(PROJECT) \
--region=$(REGION) \ --region=$(REGION) \
--service-account=projects/$(PROJECT)/serviceAccounts/cb-image@$(PROJECT).iam.gserviceaccount.com \ --service-account=projects/$(PROJECT)/serviceAccounts/cb-image@$(PROJECT).iam.gserviceaccount.com \
--substitutions=_REGION=$(REGION),_ZONE=$(ZONE) --gcs-source-staging-dir=gs://$(PROJECT)-gitea-build-source/source \
--substitutions=_REGION=$(REGION),_ZONE=$(ZONE),SHORT_SHA=$(shell git rev-parse --short=7 HEAD)
.PHONY: rollout .PHONY: rollout
rollout: ## Pull the latest :prod images onto the VM right now rollout: ## Pull the latest :prod images onto the VM right now
+19 -5
View File
@@ -47,14 +47,23 @@ printf %s '<token>' | gcloud secrets versions add github-pat --data-file=- --pro
# 3. Confirm the Cloud DNS zone is authoritative. DNS-01 cannot work otherwise. # 3. Confirm the Cloud DNS zone is authoritative. DNS-01 cannot work otherwise.
dig NS gitea.jasonmross.dev dig NS gitea.jasonmross.dev
# 4. Configure and apply. # 4. The ACME contact address. Kept in Secret Manager, not stack config, so it
# stays out of this public repo; the VM reads it when rendering the Caddyfile.
printf %s 'you@example.com' | gcloud secrets versions add gitea-acme-email --data-file=- --project <project-id>
# 5. Configure and apply. Pulumi's GCS backend and Google provider use
# Application Default Credentials, not your gcloud login.
gcloud auth application-default login
# Use the passphrase bootstrap.sh generated. Letting `stack init` prompt for a
# new one encrypts the stack with a key Cloud Build's infra trigger never sees.
export PULUMI_CONFIG_PASSPHRASE=$(gcloud secrets versions access latest \
--secret=pulumi-config-passphrase --project <project-id>)
cd infra cd infra
pulumi login gs://<project-id>-pulumi-state pulumi login gs://<project-id>-pulumi-state
pulumi stack init prod pulumi stack init prod
pulumi config set gcp:project <project-id> pulumi config set gcp:project <project-id>
pulumi config set gitea:domain gitea.jasonmross.dev pulumi config set gitea:domain gitea.jasonmross.dev
pulumi config set gitea:dnsZone <cloud-dns-managed-zone-name> # gcloud dns managed-zones list pulumi config set gitea:dnsZone <cloud-dns-managed-zone-name> # gcloud dns managed-zones list
pulumi config set gitea:acmeEmail you@example.com
pulumi config set gitea:githubOwner <owner> pulumi config set gitea:githubOwner <owner>
pulumi config set gitea:githubAppInstallationId <id> pulumi config set gitea:githubAppInstallationId <id>
pulumi config set gitea:infraBuildServiceAccount cb-infra@<project-id>.iam.gserviceaccount.com pulumi config set gitea:infraBuildServiceAccount cb-infra@<project-id>.iam.gserviceaccount.com
@@ -62,10 +71,10 @@ pulumi config set gitea:infraBuildServiceAccount cb-infra@<project-id>.iam.gserv
pulumi config set gitea:wafMode DetectionOnly pulumi config set gitea:wafMode DetectionOnly
pulumi up pulumi up
# 5. First image build. Until this runs, the :prod images do not exist. # 6. First image build. Until this runs, the :prod images do not exist.
cd .. && make build cd .. && make build
# 6. Create the admin user. # 7. Create the admin user.
make ssh make ssh
sudo podman exec -u 1000 gitea gitea admin user create \ sudo podman exec -u 1000 gitea gitea admin user create \
-c /etc/gitea/app.ini --admin --username <you> --email <you@example.com> --random-password -c /etc/gitea/app.ini --admin --username <you> --email <you@example.com> --random-password
@@ -73,7 +82,7 @@ sudo podman exec -u 1000 gitea gitea admin user create \
### Expected on the first run, not a bug ### Expected on the first run, not a bug
Between step 4 and step 5 the `:prod` images do not exist yet, so `gitea.service` Between step 5 and step 6 the `:prod` images do not exist yet, so `gitea.service`
and `caddy.service` crash-loop. That is intentional: the units carry and `caddy.service` crash-loop. That is intentional: the units carry
`Restart=always` with `StartLimitIntervalSec=0`, so they recover on their own `Restart=always` with `StartLimitIntervalSec=0`, so they recover on their own
within 30 seconds of the first successful push. Likewise, `app.ini` is not within 30 seconds of the first successful push. Likewise, `app.ini` is not
@@ -91,6 +100,11 @@ make backup # on-demand gitea dump to GCS
make ssh # shell via IAP make ssh # shell via IAP
``` ```
The targets read the project and zone from the Pulumi stack, which needs
Application Default Credentials (`gcloud auth application-default login`).
Without them `pulumi config get` fails quietly and gcloud runs with an empty
`--project=`; pass `PROJECT=<project-id>` to skip the lookup.
A push to `main` under `image/**` builds, pushes, rolls out, and gates on A push to `main` under `image/**` builds, pushes, rolls out, and gates on
`/api/healthz`. A push under `infra/**` or `vm/**` runs `pulumi up` and then `/api/healthz`. A push under `infra/**` or `vm/**` runs `pulumi up` and then
re-syncs the VM configuration. Anything else does nothing. re-syncs the VM configuration. Anything else does nothing.
+4
View File
@@ -36,6 +36,9 @@ steps:
- id: build-gitea - id: build-gitea
name: gcr.io/cloud-builders/docker name: gcr.io/cloud-builders/docker
# Both Dockerfiles are written for BuildKit (`# syntax=`, COPY --chmod). This
# builder image defaults to the legacy builder, which rejects --chmod.
env: [DOCKER_BUILDKIT=1]
entrypoint: bash entrypoint: bash
args: args:
- -c - -c
@@ -52,6 +55,7 @@ steps:
- id: build-caddy - id: build-caddy
name: gcr.io/cloud-builders/docker name: gcr.io/cloud-builders/docker
env: [DOCKER_BUILDKIT=1]
entrypoint: bash entrypoint: bash
# xcaddy runs inside the Dockerfile's golang builder stage, so the plain # xcaddy runs inside the Dockerfile's golang builder stage, so the plain
# docker builder is all this step needs -- no Go toolchain out here. # docker builder is all this step needs -- no Go toolchain out here.
+4
View File
@@ -29,6 +29,10 @@ steps:
- -c - -c
- | - |
set -euo pipefail set -euo pipefail
# Pulumi.yaml points the go runtime at a prebuilt binary, so Pulumi
# runs ./gitea-infra rather than compiling the program itself.
go build -o gitea-infra .
# Self-managed GCS backend: no external SaaS dependency, and the state # Self-managed GCS backend: no external SaaS dependency, and the state
# bucket is versioned so history is recoverable. # bucket is versioned so history is recoverable.
pulumi login "gs://$PROJECT_ID-pulumi-state" pulumi login "gs://$PROJECT_ID-pulumi-state"
+7
View File
@@ -58,6 +58,13 @@ curl -vI https://gitea.jasonmross.dev # valid Let's Encrypt cert
DNS-01 means renewal does not need inbound port 80 at all. That is testable: DNS-01 means renewal does not need inbound port 80 at all. That is testable:
temporarily remove the `gitea-allow-web` port 80 rule and force a renewal. temporarily remove the `gitea-allow-web` port 80 rule and force a renewal.
The ACME account and certificates live in the `caddy-data` podman volume, under
`/var/lib/containers` on the **boot** disk, not the data disk. Replacing the
instance therefore re-registers and re-issues on first start. That is fine
occasionally, but Let's Encrypt allows 5 duplicate certificates per week, so
several replacements in a few days can lock issuance out until the window
rolls over.
### fail2ban — drill it, do not trust the status output ### fail2ban — drill it, do not trust the status output
```bash ```bash
+4 -10
View File
@@ -4,15 +4,12 @@
# infrastructure metadata. The Gitea application secrets live in Secret Manager # infrastructure metadata. The Gitea application secrets live in Secret Manager
# and are never read by this program. # and are never read by this program.
config: config:
gcp:project: CHANGEME-gitea-project-id gcp:project: gitea-496920
gcp:region: us-east1 gcp:region: us-east1
gitea:domain: gitea.jasonmross.dev gitea:domain: gitea.jasonmross.dev
# The Cloud DNS *resource* name of the existing managed zone, which is not # The Cloud DNS *resource* name of the existing managed zone, which is not
# necessarily the DNS name. `gcloud dns managed-zones list` to find it. # necessarily the DNS name. `gcloud dns managed-zones list` to find it.
gitea:dnsZone: CHANGEME-managed-zone-name gitea:dnsZone: main
gitea:acmeEmail: CHANGEME@example.com
# us-east1 has zones b, c and d -- there is no us-east1-a. # us-east1 has zones b, c and d -- there is no us-east1-a.
gitea:zone: us-east1-b gitea:zone: us-east1-b
# e2-small: 2 shared vCPU, 2 GB RAM. See docs/runbook.md ("Memory on a 2 GB # e2-small: 2 shared vCPU, 2 GB RAM. See docs/runbook.md ("Memory on a 2 GB
@@ -20,23 +17,20 @@ config:
gitea:machineType: e2-small gitea:machineType: e2-small
gitea:bootDiskGb: "20" gitea:bootDiskGb: "20"
gitea:dataDiskGb: "30" gitea:dataDiskGb: "30"
gitea:appName: Gitea gitea:appName: Gitea
gitea:requireSigninView: "false" gitea:requireSigninView: "false"
gitea:podmanSubnet: 10.89.10.0/24 gitea:podmanSubnet: 10.89.10.0/24
# Coraza WAF: On | DetectionOnly | Off. # Coraza WAF: On | DetectionOnly | Off.
# Start in DetectionOnly, review what it flags (docs/waf.md), then switch to # Start in DetectionOnly, review what it flags (docs/waf.md), then switch to
# On. The fail2ban jail that bans on WAF verdicts follows this value. # On. The fail2ban jail that bans on WAF verdicts follows this value.
gitea:wafMode: DetectionOnly gitea:wafMode: DetectionOnly
# Cloud Build source. The GitHub App installation id comes from the URL of the # Cloud Build source. The GitHub App installation id comes from the URL of the
# app's settings page after you install it on the repository. # app's settings page after you install it on the repository.
gitea:githubOwner: JMR-dev gitea:githubOwner: JMR-dev
gitea:githubRepo: Gitea gitea:githubRepo: Gitea
gitea:githubAppInstallationId: "0" gitea:githubAppInstallationId: "0"
gitea:githubPatSecret: github-pat gitea:githubPatSecret: github-pat
# Created by scripts/bootstrap.sh before the first `pulumi up`, because it is # Created by scripts/bootstrap.sh before the first `pulumi up`, because it is
# the identity that runs Pulumi and therefore cannot be created by Pulumi. # the identity that runs Pulumi and therefore cannot be created by Pulumi.
gitea:infraBuildServiceAccount: CHANGEME@CHANGEME.iam.gserviceaccount.com gitea:infraBuildServiceAccount: cb-infra@gitea-496920.iam.gserviceaccount.com
encryptionsalt: v1:pIXPmM64Bzc=:v1:0pkb4B2RVM5LFu2v:ZEPaG4RB9ySlpmaHkaBy8v6FQ3paHg==
+26 -26
View File
@@ -1,8 +1,8 @@
module gitea-infra module gitea-infra
go 1.25.11 go 1.26.0
toolchain go1.26.6 toolchain go1.26.9
require ( require (
github.com/pulumi/pulumi-gcp/sdk/v9 v9.34.1 github.com/pulumi/pulumi-gcp/sdk/v9 v9.34.1
@@ -40,14 +40,14 @@ require (
github.com/go-git/gcfg/v2 v2.0.2 // indirect github.com/go-git/gcfg/v2 v2.0.2 // indirect
github.com/go-git/go-billy/v6 v6.0.0-alpha.2 // indirect github.com/go-git/go-billy/v6 v6.0.0-alpha.2 // indirect
github.com/go-git/go-git/v6 v6.0.0-alpha.5 // indirect github.com/go-git/go-git/v6 v6.0.0-alpha.5 // indirect
github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/logr v1.4.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/godbus/dbus/v5 v5.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.5 // indirect github.com/golang/glog v1.2.5 // indirect
github.com/google/go-tpm v0.9.8 // indirect github.com/google/go-tpm v0.9.8 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -93,30 +93,30 @@ require (
go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect
go.opentelemetry.io/collector/featuregate v1.53.0 // indirect go.opentelemetry.io/collector/featuregate v1.53.0 // indirect
go.opentelemetry.io/collector/pdata v1.53.0 // indirect go.opentelemetry.io/collector/pdata v1.53.0 // indirect
go.opentelemetry.io/contrib/bridges/otelslog v0.18.0 // indirect go.opentelemetry.io/contrib/bridges/otelslog v0.20.1 // indirect
go.opentelemetry.io/otel v1.44.0 // indirect go.opentelemetry.io/otel v1.46.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 // indirect
go.opentelemetry.io/otel/log v0.19.0 // indirect go.opentelemetry.io/otel/log v0.22.0 // indirect
go.opentelemetry.io/otel/metric v1.44.0 // indirect go.opentelemetry.io/otel/metric v1.46.0 // indirect
go.opentelemetry.io/otel/sdk v1.43.0 // indirect go.opentelemetry.io/otel/sdk v1.45.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.19.0 // indirect go.opentelemetry.io/otel/sdk/log v0.21.0 // indirect
go.opentelemetry.io/otel/trace v1.44.0 // indirect go.opentelemetry.io/otel/trace v1.46.0 // indirect
go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.opentelemetry.io/proto/otlp v1.11.0 // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.54.0 // indirect golang.org/x/crypto v0.57.0 // indirect
golang.org/x/mod v0.38.0 // indirect golang.org/x/mod v0.41.0 // indirect
golang.org/x/net v0.57.0 // indirect golang.org/x/net v0.60.0 // indirect
golang.org/x/sync v0.22.0 // indirect golang.org/x/sync v0.23.0 // indirect
golang.org/x/sys v0.47.0 // indirect golang.org/x/sys v0.48.0 // indirect
golang.org/x/term v0.45.0 // indirect golang.org/x/term v0.46.0 // indirect
golang.org/x/text v0.40.0 // indirect golang.org/x/text v0.42.0 // indirect
golang.org/x/tools v0.47.0 // indirect golang.org/x/tools v0.49.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect
google.golang.org/grpc v1.82.1 // indirect google.golang.org/grpc v1.83.2 // indirect
google.golang.org/protobuf v1.36.11 // indirect google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/frand v1.4.2 // indirect lukechampine.com/frand v1.4.2 // indirect
+57 -57
View File
@@ -76,8 +76,8 @@ github.com/go-git/go-git-fixtures/v6 v6.0.0-alpha.1/go.mod h1:ECf1MqJlBdYpKggBrO
github.com/go-git/go-git/v6 v6.0.0-alpha.5 h1:sE+OlkHgYWNMVmN1s9sR7uyFgsWLtxcNWse/vBYKxRE= github.com/go-git/go-git/v6 v6.0.0-alpha.5 h1:sE+OlkHgYWNMVmN1s9sR7uyFgsWLtxcNWse/vBYKxRE=
github.com/go-git/go-git/v6 v6.0.0-alpha.5/go.mod h1:3IjhiZnM+uBmUrOGSeqrJpsmi4Vd0H2NZO/uK2a7d0s= github.com/go-git/go-git/v6 v6.0.0-alpha.5/go.mod h1:3IjhiZnM+uBmUrOGSeqrJpsmi4Vd0H2NZO/uK2a7d0s=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
@@ -98,8 +98,8 @@ github.com/google/go-tpm-tools v0.3.13-0.20230620182252-4639ecce2aba/go.mod h1:E
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 h1:5VipnvEpbqr2gA2VbM+nYVbkIF28c5ZQfqCBQ5g2xfk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -128,9 +128,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@@ -176,7 +175,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk= github.com/pkg/term v1.1.0 h1:xIAAdCMh3QIAy+5FrE8Ad8XoDhEU4ufwbaSozViP9kk=
github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw= github.com/pkg/term v1.1.0/go.mod h1:E25nymQcrSllhX42Ok8MRm1+hyBdHY0dCeiKZ9jpNGw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 h1:vkHw5I/plNdTr435cARxCW6q9gc0S/Yxz7Mkd38pOb0= github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 h1:vkHw5I/plNdTr435cARxCW6q9gc0S/Yxz7Mkd38pOb0=
github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231/go.mod h1:murToZ2N9hNJzewjHBgfFdXhZKjY3z5cYC1VXk+lbFE= github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231/go.mod h1:murToZ2N9hNJzewjHBgfFdXhZKjY3z5cYC1VXk+lbFE=
@@ -207,8 +205,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.12.1/go.mod h1:MDEgiDPPsNp5cuIrHPPCyornHKgEVbtFUmoNlxoYthg=
github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U= github.com/texttheater/golang-levenshtein v1.0.1 h1:+cRNoVrfiwufQPhoMzB6N0Yf/Mqajr6t1lOv8GyGE2U=
github.com/texttheater/golang-levenshtein v1.0.1/go.mod h1:PYAKrbF5sAiq9wd+H82hs7gNaen0CplQ9uvm6+enD/8= github.com/texttheater/golang-levenshtein v1.0.1/go.mod h1:PYAKrbF5sAiq9wd+H82hs7gNaen0CplQ9uvm6+enD/8=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
@@ -231,32 +229,32 @@ go.opentelemetry.io/collector/internal/testutil v0.147.0 h1:DFlRxBRp23/sZnpTITK2
go.opentelemetry.io/collector/internal/testutil v0.147.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE= go.opentelemetry.io/collector/internal/testutil v0.147.0/go.mod h1:Jkjs6rkqs973LqgZ0Fe3zrokQRKULYXPIf4HuqStiEE=
go.opentelemetry.io/collector/pdata v1.53.0 h1:DlYDbRwammEZaxDZHINx5v0n8SEOVNniPbi6FRTlVkA= go.opentelemetry.io/collector/pdata v1.53.0 h1:DlYDbRwammEZaxDZHINx5v0n8SEOVNniPbi6FRTlVkA=
go.opentelemetry.io/collector/pdata v1.53.0/go.mod h1:LRSYGNjKXaUrZEwZv3Yl+8/zV2HmRGKXW62zB2bysms= go.opentelemetry.io/collector/pdata v1.53.0/go.mod h1:LRSYGNjKXaUrZEwZv3Yl+8/zV2HmRGKXW62zB2bysms=
go.opentelemetry.io/contrib/bridges/otelslog v0.18.0 h1:hhPGP3zvvy1xWT9RTy970wlniSxFttBIsAK1gvMguJM= go.opentelemetry.io/contrib/bridges/otelslog v0.20.1 h1:5sHc4ToTFjfSZCtGAAM6jPunICAmJX73htv372T4ipc=
go.opentelemetry.io/contrib/bridges/otelslog v0.18.0/go.mod h1:twJF7inoMza6kxMcF8JOdL3mPmtOZu7GEr34CUNE6Dg= go.opentelemetry.io/contrib/bridges/otelslog v0.20.1/go.mod h1:oa6kgvyz/3GYW04dohd0++xJIH4xdQY8PAbpeCMaM8M=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= go.opentelemetry.io/otel v1.46.0/go.mod h1:Gj3SEScelsNC45tp4nSxRYlS+f5iez7W8XPMCt905kE=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0 h1:Dn8rkudDzY6KV9dr/D/bTUuWgqDf9xe0rr4G2elrn0Y= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0 h1:WseeVYf5dJZTsyPiyW5L14k5qsSibqXAMTSiFEDiWr0=
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.19.0/go.mod h1:gMk9F0xDgyN9M/3Ed5Y1wKcx/9mlU91NXY2SNq7RQuU= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.21.0/go.mod h1:SiLZnQS6Qk2eCpvr2CH/XMAOa64TWGXxEZJZCpD2Lmc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0 h1:QRefszxJmfPdjXUUm3j6iDzY03mTPXMjqErFqQ67vUg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.45.0/go.mod h1:Tiz03lTBVBrm7eWZBOidzEaYaJa8tjwGUGv6d8mlTyk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0 h1:mq/Qcf28TWz719lE3/hMB4KkyDuLJIvgJnFGcd0kEUI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0 h1:fG5MCxGz8+2VtrN/WgqSpJFctVz24gpxj8CxkKmc8Ww=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.41.0/go.mod h1:yk5LXEYhsL2htyDNJbEq7fWzNEigeEdV5xBF/Y+kAv0= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.45.0/go.mod h1:BmAYTn+3ysbRe+IU2msxmf5Rx3g6DHvex+tWI3LdhYI=
go.opentelemetry.io/otel/log v0.19.0 h1:KUZs/GOsw79TBBMfDWsXS+KZ4g2Ckzksd1ymzsIEbo4= go.opentelemetry.io/otel/log v0.22.0 h1:5DBNnfvaJ6CVdkJ+Jle8Tzs50aSSv49TXGj9XRsEYw0=
go.opentelemetry.io/otel/log v0.19.0/go.mod h1:5DQYeGmxVIr4n0/BcJvF4upsraHjg6vudJJpnkL6Ipk= go.opentelemetry.io/otel/log v0.22.0/go.mod h1:gzOt/R67vF2GniAqWu8Qv0SXy89f71muHcrkz76PCdc=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= go.opentelemetry.io/otel/metric v1.46.0/go.mod h1:iPmdWqifKUdzziPkvvzIJXITl56fQx2mGM/DHLB3/2o=
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= go.opentelemetry.io/otel/sdk v1.45.0 h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw=
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= go.opentelemetry.io/otel/sdk v1.45.0/go.mod h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA=
go.opentelemetry.io/otel/sdk/log v0.19.0 h1:scYVLqT22D2gqXItnWiocLUKGH9yvkkeql5dBDiXyko= go.opentelemetry.io/otel/sdk/log v0.21.0 h1:QsE7XSR0ktQdKmRKGnR+f1ObGF32WG+7MER/P9KgmYc=
go.opentelemetry.io/otel/sdk/log v0.19.0/go.mod h1:vFBowwXGLlW9AvpuF7bMgnNI95LiW10szrOdvzBHlAg= go.opentelemetry.io/otel/sdk/log v0.21.0/go.mod h1:m9mApjCoD2/1QuKCAptjv+BrG9WKOvQLVdNx+iBldTo=
go.opentelemetry.io/otel/sdk/log/logtest v0.19.0 h1:BEbF7ZBB6qQloV/Ub1+3NQoOUnVtcGkU3XX4Ws3GQfk= go.opentelemetry.io/otel/sdk/log/logtest v0.21.0 h1:X+JBBgKlswCGYsmgL0CnoUUtlE//VB345c84jYAYkdQ=
go.opentelemetry.io/otel/sdk/log/logtest v0.19.0/go.mod h1:Lua81/3yM0wOmoHTokLj9y9ADeA02v1naRrVrkAZuKk= go.opentelemetry.io/otel/sdk/log/logtest v0.21.0/go.mod h1:HD1575K8e6sIFBBDd5tZB3t9DlMytWXq9FuR+Y4rfjE=
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= go.opentelemetry.io/otel/sdk/metric v1.45.0 h1:oVFszMfyj1Am6s24Vtc7wBb8BKLcwepJjNEYILuiE3o=
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= go.opentelemetry.io/otel/sdk/metric v1.45.0/go.mod h1:vUWUxDZvu1WVRj8JA8S0AdhsPrZoDpA2DdZauIh4mDA=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/otel/trace v1.46.0/go.mod h1:J7GAXweO77XSFkB/rmAqk9D6ihszhFjLU+d9WuUxDLI=
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.11.0 h1:5rrYs0Ykyj50sdU/JU0x8etU+LubXWb+gED6TbEdMIk=
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= go.opentelemetry.io/proto/otlp v1.11.0/go.mod h1:SmVizdCOAm3XBtG1g1NnOdhW6jtddT72hLMhv8VwA8E=
go.opentelemetry.io/proto/slim/otlp v1.9.0 h1:fPVMv8tP3TrsqlkH1HWYUpbCY9cAIemx184VGkS6vlE= go.opentelemetry.io/proto/slim/otlp v1.9.0 h1:fPVMv8tP3TrsqlkH1HWYUpbCY9cAIemx184VGkS6vlE=
go.opentelemetry.io/proto/slim/otlp v1.9.0/go.mod h1:xXdeJJ90Gqyll+orzUkY4bOd2HECo5JofeoLpymVqdI= go.opentelemetry.io/proto/slim/otlp v1.9.0/go.mod h1:xXdeJJ90Gqyll+orzUkY4bOd2HECo5JofeoLpymVqdI=
go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0 h1:o13nadWDNkH/quoDomDUClnQBpdQQ2Qqv0lQBjIXjE8= go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0 h1:o13nadWDNkH/quoDomDUClnQBpdQQ2Qqv0lQBjIXjE8=
@@ -270,31 +268,33 @@ go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.38.0 h1:MECBjubtXD7yj4HrhIUcywNaGeNVUdfVnxmPajOk4yk= golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c=
golang.org/x/mod v0.38.0/go.mod h1:V6Xz0pq8TQ3dGqVQ1FVHuelZpAL0uNhSkk9ogYP3c40= golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= golang.org/x/net v0.60.0 h1:79p50tfZlm0J9YfoDsSi639qSXNGVwEzOPLCxM2FsYU=
golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= golang.org/x/net v0.60.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -305,34 +305,34 @@ golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE=
golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec= google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d h1:FarXi840EJWSHYTN3ERkADbPWjl307+FGrA22KAVjjc=
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc= google.golang.org/genproto/googleapis/api v0.0.0-20260803160001-6ac0973c030d/go.mod h1:K/+WGbmBY7aNW1HDw1fJnKYo10i0DkAX6pows00dLig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw= google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU=
google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+7
View File
@@ -63,6 +63,9 @@ func main() {
if err := iam.GrantSecrets(ctx, cfg, accounts, secrets.Names); err != nil { if err := iam.GrantSecrets(ctx, cfg, accounts, secrets.Names); err != nil {
return err return err
} }
if err := iam.GrantSecretRead(ctx, cfg, accounts, secrets.ACMEEmail); err != nil {
return err
}
buckets, err := storage.New(ctx, cfg, vmDir, apis) buckets, err := storage.New(ctx, cfg, vmDir, apis)
if err != nil { if err != nil {
@@ -71,6 +74,9 @@ func main() {
if err := iam.GrantBuckets(ctx, accounts, buckets.Config, buckets.Backup); err != nil { if err := iam.GrantBuckets(ctx, accounts, buckets.Config, buckets.Backup); err != nil {
return err return err
} }
if err := iam.GrantBuildSource(ctx, accounts, buckets.BuildSource); err != nil {
return err
}
// The zone already exists and is delegated; this only adds the A record // The zone already exists and is delegated; this only adds the A record
// and the zone-scoped permission Caddy needs for DNS-01. // and the zone-scoped permission Caddy needs for DNS-01.
@@ -97,6 +103,7 @@ func main() {
ctx.Export("registry", pulumi.Sprintf("%s/%s/%s", cfg.ARHost(), cfg.Project, registry.RepoID)) ctx.Export("registry", pulumi.Sprintf("%s/%s/%s", cfg.ARHost(), cfg.Project, registry.RepoID))
ctx.Export("configBucket", buckets.Config.Name) ctx.Export("configBucket", buckets.Config.Name)
ctx.Export("backupBucket", buckets.Backup.Name) ctx.Export("backupBucket", buckets.Backup.Name)
ctx.Export("buildSourceBucket", buckets.BuildSource.Name)
ctx.Export("configHash", pulumi.String(buckets.ConfigHash)) ctx.Export("configHash", pulumi.String(buckets.ConfigHash))
ctx.Export("vmServiceAccount", accounts.VM.Email) ctx.Export("vmServiceAccount", accounts.VM.Email)
ctx.Export("imageServiceAccount", accounts.Image.Email) ctx.Export("imageServiceAccount", accounts.Image.Email)
-1
View File
@@ -169,7 +169,6 @@ func New(
"image-caddy": pulumi.String(imageCaddy), "image-caddy": pulumi.String(imageCaddy),
"domain": pulumi.String(cfg.Domain), "domain": pulumi.String(cfg.Domain),
"acme-email": pulumi.String(cfg.ACMEEmail),
"app-name": pulumi.String(cfg.AppName), "app-name": pulumi.String(cfg.AppName),
"require-signin-view": pulumi.String(strconv.FormatBool(cfg.RequireSigninView)), "require-signin-view": pulumi.String(strconv.FormatBool(cfg.RequireSigninView)),
-2
View File
@@ -18,7 +18,6 @@ type Config struct {
Domain string Domain string
DNSZone string DNSZone string
ACMEEmail string
AppName string AppName string
PodmanCIDR string PodmanCIDR string
@@ -51,7 +50,6 @@ func Load(ctx *pulumi.Context) (*Config, error) {
Zone: c.Get("zone"), Zone: c.Get("zone"),
Domain: c.Require("domain"), Domain: c.Require("domain"),
DNSZone: c.Require("dnsZone"), DNSZone: c.Require("dnsZone"),
ACMEEmail: c.Require("acmeEmail"),
AppName: c.Get("appName"), AppName: c.Get("appName"),
PodmanCIDR: c.Get("podmanSubnet"), PodmanCIDR: c.Get("podmanSubnet"),
+15
View File
@@ -8,6 +8,7 @@ package dns
import ( import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute" "github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns" "github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi" "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"gitea-infra/pkg/config" "gitea-infra/pkg/config"
@@ -60,5 +61,19 @@ func New(
return nil, err return nil, err
} }
// The zone-scoped grant is not enough on its own: the googleclouddns plugin
// maps the domain to a zone by LISTING the project's managed zones, and a
// list is a project-level permission that no zone binding can confer. Without
// this, presenting the challenge fails with a bare 403. dns.reader adds
// read-only access and nothing else, and every write stays scoped to the zone
// above.
if _, err := projects.NewIAMMember(ctx, "gitea-vm-dns-reader", &projects.IAMMemberArgs{
Project: pulumi.String(cfg.Project),
Role: pulumi.String("roles/dns.reader"),
Member: pulumi.Sprintf("serviceAccount:%s", vmServiceAccountEmail),
}, pulumi.DependsOn(deps)); err != nil {
return nil, err
}
return &DNS{Zone: zone, Record: rec}, nil return &DNS{Zone: zone, Record: rec}, nil
} }
+25 -6
View File
@@ -123,12 +123,7 @@ func GrantRegistry(ctx *pulumi.Context, cfg *config.Config, a *Accounts, repo *a
// scripts/bootstrap.sh, not by Pulumi; see package secrets for why. // scripts/bootstrap.sh, not by Pulumi; see package secrets for why.
func GrantSecrets(ctx *pulumi.Context, cfg *config.Config, a *Accounts, names []string) error { func GrantSecrets(ctx *pulumi.Context, cfg *config.Config, a *Accounts, names []string) error {
for _, name := range names { for _, name := range names {
if _, err := secretmanager.NewSecretIamMember(ctx, "vm-read-"+name, &secretmanager.SecretIamMemberArgs{ if err := GrantSecretRead(ctx, cfg, a, name); err != nil {
Project: pulumi.String(cfg.Project),
SecretId: pulumi.String(name),
Role: pulumi.String("roles/secretmanager.secretAccessor"),
Member: pulumi.Sprintf("serviceAccount:%s", a.VM.Email),
}); err != nil {
return err return err
} }
// vm/bootstrap.sh's safety net adds a version if one is somehow missing. // vm/bootstrap.sh's safety net adds a version if one is somehow missing.
@@ -144,6 +139,30 @@ func GrantSecrets(ctx *pulumi.Context, cfg *config.Config, a *Accounts, names []
return nil return nil
} }
// GrantSecretRead gives the VM read-only access to one secret. On its own it is
// for operator-supplied values the VM must never write; GrantSecrets adds
// version-adder on top for the ones it may generate.
func GrantSecretRead(ctx *pulumi.Context, cfg *config.Config, a *Accounts, name string) error {
_, err := secretmanager.NewSecretIamMember(ctx, "vm-read-"+name, &secretmanager.SecretIamMemberArgs{
Project: pulumi.String(cfg.Project),
SecretId: pulumi.String(name),
Role: pulumi.String("roles/secretmanager.secretAccessor"),
Member: pulumi.Sprintf("serviceAccount:%s", a.VM.Email),
})
return err
}
// GrantBuildSource lets cb-image@ read the tarballs `make build` stages, and
// nothing else in storage. See storage.New for why the bucket exists.
func GrantBuildSource(ctx *pulumi.Context, a *Accounts, sourceBucket *storage.Bucket) error {
_, err := storage.NewBucketIAMMember(ctx, "img-build-source-reader", &storage.BucketIAMMemberArgs{
Bucket: sourceBucket.Name,
Role: pulumi.String("roles/storage.objectViewer"),
Member: pulumi.Sprintf("serviceAccount:%s", a.Image.Email),
})
return err
}
// GrantBuckets: read-only on config, write-only on backups. The VM can create a // GrantBuckets: read-only on config, write-only on backups. The VM can create a
// backup but cannot read or delete existing ones, which limits what ransomware // backup but cannot read or delete existing ones, which limits what ransomware
// on the box could do to the backup history. // on the box could do to the backup history.
+6
View File
@@ -26,3 +26,9 @@ var Names = []string{
"gitea-oauth2-jwt-secret", "gitea-oauth2-jwt-secret",
"gitea-lfs-jwt-secret", "gitea-lfs-jwt-secret",
} }
// ACMEEmail holds the contact address Caddy registers with Let's Encrypt. It
// is a secret not because it signs anything but to keep it out of this public
// repository and out of instance metadata. Unlike Names it is supplied by the
// operator, never generated, so the VM gets read access only.
const ACMEEmail = "gitea-acme-email"
+29 -2
View File
@@ -1,4 +1,4 @@
// Package storage holds the two buckets and, importantly, uploads the vm/ tree // Package storage holds the buckets and, importantly, uploads the vm/ tree
// as Pulumi-managed objects. // as Pulumi-managed objects.
// //
// Uploading the VM configuration through Pulumi (rather than a `gcloud storage // Uploading the VM configuration through Pulumi (rather than a `gcloud storage
@@ -24,6 +24,8 @@ import (
type Buckets struct { type Buckets struct {
Config *storage.Bucket Config *storage.Bucket
Backup *storage.Bucket Backup *storage.Bucket
// BuildSource stages the source tarball for `make build`. See New.
BuildSource *storage.Bucket
// ConfigHash changes whenever any file under vm/ changes. It is written into // ConfigHash changes whenever any file under vm/ changes. It is written into
// instance metadata so a config change is visible from `describe`, and so // instance metadata so a config change is visible from `describe`, and so
// there is something to compare against when debugging drift. // there is something to compare against when debugging drift.
@@ -72,12 +74,37 @@ func New(ctx *pulumi.Context, cfg *config.Config, vmDir string, deps []pulumi.Re
return nil, err return nil, err
} }
// Where `gcloud builds submit` stages its source tarball. Builds run as
// cb-image@, which needs storage.objects.get on that tarball. The default
// staging bucket is <project>_cloudbuild, created by gcloud on the first
// submit -- after `pulumi up`, so there is nothing to bind to in advance --
// and project-wide objectViewer would also open the backup and state
// buckets. A dedicated bucket keeps the grant exact. Triggered builds fetch
// source through the GitHub connection and never touch it.
buildSourceBucket, err := storage.NewBucket(ctx, "gitea-build-source", &storage.BucketArgs{
Name: pulumi.Sprintf("%s-gitea-build-source", cfg.Project),
Location: pulumi.String(strings.ToUpper(cfg.Region)),
UniformBucketLevelAccess: pulumi.Bool(true),
PublicAccessPrevention: pulumi.String("enforced"),
// Tarballs are only read once, by the build they were uploaded for.
LifecycleRules: storage.BucketLifecycleRuleArray{
&storage.BucketLifecycleRuleArgs{
Action: &storage.BucketLifecycleRuleActionArgs{Type: pulumi.String("Delete")},
Condition: &storage.BucketLifecycleRuleConditionArgs{Age: pulumi.Int(7)},
},
},
ForceDestroy: pulumi.Bool(true),
}, opts)
if err != nil {
return nil, err
}
hash, err := uploadTree(ctx, configBucket, vmDir) hash, err := uploadTree(ctx, configBucket, vmDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Buckets{Config: configBucket, Backup: backupBucket, ConfigHash: hash}, nil return &Buckets{Config: configBucket, Backup: backupBucket, BuildSource: buildSourceBucket, ConfigHash: hash}, nil
} }
// uploadTree mirrors vmDir into gs://<bucket>/vm/ and returns a content hash of // uploadTree mirrors vmDir into gs://<bucket>/vm/ and returns a content hash of
+11 -1
View File
@@ -99,6 +99,16 @@ if ! has_version github-pat; then
echo " printf %s '<token>' | gcloud secrets versions add github-pat --project=${PROJECT} --data-file=-" echo " printf %s '<token>' | gcloud secrets versions add github-pat --project=${PROJECT} --data-file=-"
fi fi
# The ACME contact address Caddy registers with Let's Encrypt. A secret only to
# keep it out of this public repository and out of instance metadata. Created
# empty: the address is yours to choose, not something to generate.
ensure_secret gitea-acme-email
if ! has_version gitea-acme-email; then
echo " NOTE: secret 'gitea-acme-email' has no value yet. Caddy still issues"
echo " certificates without it, but with no contact address. Set it with:"
echo " printf %s 'you@example.com' | gcloud secrets versions add gitea-acme-email --project=${PROJECT} --data-file=-"
fi
# Gitea's signing secrets. These MUST come from `gitea generate secret`: # Gitea's signing secrets. These MUST come from `gitea generate secret`:
# INTERNAL_TOKEN is a JWT, and a random string there produces an instance that # INTERNAL_TOKEN is a JWT, and a random string there produces an instance that
# starts and then fails every internal API call in a confusing way. # starts and then fails every internal API call in a confusing way.
@@ -247,7 +257,7 @@ Next:
pulumi stack init prod pulumi stack init prod
pulumi config set gcp:project ${PROJECT} pulumi config set gcp:project ${PROJECT}
pulumi config set gitea:infraBuildServiceAccount ${INFRA_SA_EMAIL} pulumi config set gitea:infraBuildServiceAccount ${INFRA_SA_EMAIL}
# ...plus domain, dnsZone, acmeEmail, githubOwner, githubAppInstallationId # ...plus domain, dnsZone, githubOwner, githubAppInstallationId
pulumi up pulumi up
4. make build # or, spelled out: 4. make build # or, spelled out:
gcloud builds submit --config cloudbuild/image.yaml --project ${PROJECT} \\ gcloud builds submit --config cloudbuild/image.yaml --project ${PROJECT} \\
+33 -6
View File
@@ -36,7 +36,6 @@ AR_HOST=$(meta ar-host)
IMAGE_GITEA=$(meta image-gitea) IMAGE_GITEA=$(meta image-gitea)
IMAGE_CADDY=$(meta image-caddy) IMAGE_CADDY=$(meta image-caddy)
DOMAIN=$(meta domain) DOMAIN=$(meta domain)
ACME_EMAIL=$(meta acme-email)
APP_NAME=$(meta app-name) APP_NAME=$(meta app-name)
PODMAN_SUBNET=$(meta podman-subnet) PODMAN_SUBNET=$(meta podman-subnet)
PODMAN_GATEWAY=$(meta podman-gateway) PODMAN_GATEWAY=$(meta podman-gateway)
@@ -57,7 +56,7 @@ case "${WAF_MODE}" in
esac esac
: "${DATA_DISK_DEVICE:=/dev/disk/by-id/google-gitea-data}" : "${DATA_DISK_DEVICE:=/dev/disk/by-id/google-gitea-data}"
export GCP_PROJECT AR_HOST IMAGE_GITEA IMAGE_CADDY DOMAIN ACME_EMAIL APP_NAME export GCP_PROJECT AR_HOST IMAGE_GITEA IMAGE_CADDY DOMAIN APP_NAME
export PODMAN_SUBNET PODMAN_GATEWAY REQUIRE_SIGNIN_VIEW WAF_MODE export PODMAN_SUBNET PODMAN_GATEWAY REQUIRE_SIGNIN_VIEW WAF_MODE
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
@@ -199,8 +198,21 @@ setup_nftables() {
systemctl disable --now firewalld >/dev/null 2>&1 || true systemctl disable --now firewalld >/dev/null 2>&1 || true
systemctl mask firewalld >/dev/null 2>&1 || true systemctl mask firewalld >/dev/null 2>&1 || true
install -m 0600 "${STATE_DIR}/nftables/gitea.nft" /etc/sysconfig/nftables.conf [[ -n "${PODMAN_SUBNET}" && -n "${PODMAN_GATEWAY}" ]] \
nft -c -f /etc/sysconfig/nftables.conf || die "nftables ruleset failed validation" || die "podman-subnet/podman-gateway metadata missing; cannot render the ruleset"
# Validate BEFORE installing. A ruleset that fails to parse must never land
# in /etc/sysconfig: nftables.service would fail to load it on the next boot
# and the host would come up with no gitea_filter table at all.
local tmp
tmp=$(mktemp)
envsubst '${PODMAN_SUBNET} ${PODMAN_GATEWAY}' < "${STATE_DIR}/nftables/gitea.nft" > "${tmp}"
if ! nft -c -f "${tmp}"; then
rm -f "${tmp}"
die "nftables ruleset failed validation"
fi
install -m 0600 "${tmp}" /etc/sysconfig/nftables.conf
rm -f "${tmp}"
systemctl enable --now nftables systemctl enable --now nftables
systemctl reload nftables systemctl reload nftables
@@ -429,6 +441,20 @@ render_all() {
rm -f /etc/sysctl.d/90-gitea-caddy.conf rm -f /etc/sysctl.d/90-gitea-caddy.conf
fi fi
# The ACME contact address lives in Secret Manager rather than instance
# metadata, to keep it out of the public repository. Without it Caddy still
# issues certificates, just under an account with no contact address -- far
# better than an empty `email` directive, which fails to parse and leaves
# nothing serving TLS.
local acme_email caddy_email
if acme_email=$(gcloud secrets versions access latest --secret=gitea-acme-email \
--project="${GCP_PROJECT}" 2>/dev/null) && [[ -n "${acme_email}" ]]; then
caddy_email="email ${acme_email}"
else
warn "secret gitea-acme-email unreadable -- Caddy will register without a contact address"
caddy_email="# no ACME contact address: secret gitea-acme-email was unreadable at render time"
fi
# Trust both the bridge CIDR and loopback so this value stays correct in # Trust both the bridge CIDR and loopback so this value stays correct in
# either Caddy networking mode. Rootful podman SNATs host-loopback traffic # either Caddy networking mode. Rootful podman SNATs host-loopback traffic
# to the bridge gateway, so the CIDR covers the host-network case too. # to the bridge gateway, so the CIDR covers the host-network case too.
@@ -444,7 +470,8 @@ render_all() {
GITEA_UPSTREAM="${gitea_upstream}" \ GITEA_UPSTREAM="${gitea_upstream}" \
CADDY_NETWORK="${caddy_network}" \ CADDY_NETWORK="${caddy_network}" \
CADDY_PUBLISH_PORTS="${caddy_publish}" \ CADDY_PUBLISH_PORTS="${caddy_publish}" \
CADDY_SYSCTL="${caddy_sysctl}" CADDY_SYSCTL="${caddy_sysctl}" \
CADDY_EMAIL="${caddy_email}"
# app.ini is 0400 owned by uid 1000: it holds SECRET_KEY and INTERNAL_TOKEN, # app.ini is 0400 owned by uid 1000: it holds SECRET_KEY and INTERNAL_TOKEN,
# and the container runs as that uid and must be able to read it. # and the container runs as that uid and must be able to read it.
@@ -453,7 +480,7 @@ render_all() {
&& changed=1 && changed=1
render "${STATE_DIR}/config/Caddyfile.tmpl" /etc/caddy/Caddyfile root:root 0644 \ render "${STATE_DIR}/config/Caddyfile.tmpl" /etc/caddy/Caddyfile root:root 0644 \
'${DOMAIN} ${ACME_EMAIL} ${GITEA_UPSTREAM} ${WAF_MODE}' \ '${DOMAIN} ${CADDY_EMAIL} ${GITEA_UPSTREAM} ${WAF_MODE}' \
&& changed=1 && changed=1
local unit local unit
+3 -2
View File
@@ -5,7 +5,7 @@
# googleclouddns -- ACME DNS-01, so issuance and renewal never need inbound 80 # googleclouddns -- ACME DNS-01, so issuance and renewal never need inbound 80
# coraza_waf -- OWASP Coraza with the Core Rule Set embedded in the binary # coraza_waf -- OWASP Coraza with the Core Rule Set embedded in the binary
{ {
email ${ACME_EMAIL} ${CADDY_EMAIL}
admin 127.0.0.1:2019 admin 127.0.0.1:2019
# Required by coraza-caddy: Caddy has no built-in ordering for a third-party # Required by coraza-caddy: Caddy has no built-in ordering for a third-party
# directive, and the WAF must run before anything that could act on the # directive, and the WAF must run before anything that could act on the
@@ -17,7 +17,8 @@ ${DOMAIN} {
tls { tls {
dns googleclouddns { dns googleclouddns {
# Application Default Credentials come from the GCE metadata server. # Application Default Credentials come from the GCE metadata server.
# The VM service account holds roles/dns.admin scoped to this zone only. # The VM service account holds roles/dns.admin scoped to this zone, plus
# project-level dns.reader so the plugin can list zones to find it.
gcp_project {env.GCP_PROJECT} gcp_project {env.GCP_PROJECT}
} }
# Only used for propagation checks. If issuance stalls waiting for # Only used for propagation checks. If issuance stalls waiting for
+10 -1
View File
@@ -1,6 +1,7 @@
#!/usr/sbin/nft -f #!/usr/sbin/nft -f
# #
# Host firewall. Installed by vm/bootstrap.sh as /etc/sysconfig/nftables.conf. # Host firewall. Rendered by vm/bootstrap.sh into /etc/sysconfig/nftables.conf,
# substituting ${PODMAN_SUBNET} and ${PODMAN_GATEWAY}.
# #
# CRITICAL: this file must NEVER contain `flush ruleset`. The stock nftables # CRITICAL: this file must NEVER contain `flush ruleset`. The stock nftables
# config ships with one, and it would wipe podman/netavark's NAT and forward # config ships with one, and it would wipe podman/netavark's NAT and forward
@@ -37,6 +38,14 @@ table inet gitea_filter {
# DHCP renewal from the GCE metadata server. # DHCP renewal from the GCE metadata server.
udp sport 67 udp dport 68 accept udp sport 67 udp dport 68 accept
# Container DNS. aardvark-dns answers on the bridge gateway, so lookups
# from containers terminate on the host and arrive here, not in forward.
# Netavark accepts them in its own table, but a packet has to survive
# every input-hook chain, and this one's drop policy would discard it
# anyway. Without this rule containers resolve nothing -- Caddy cannot
# reach Let's Encrypt and Gitea cannot reach webhook or mirror hosts.
ip saddr ${PODMAN_SUBNET} ip daddr ${PODMAN_GATEWAY} meta l4proto { tcp, udp } th dport 53 accept comment "container DNS"
# Admin SSH: IAP TCP forwarding range only. There is no other path in -- # Admin SSH: IAP TCP forwarding range only. There is no other path in --
# the VPC firewall enforces the same restriction as the outer layer. # the VPC firewall enforces the same restriction as the outer layer.
ip saddr 35.235.240.0/20 tcp dport 22 accept comment "IAP SSH" ip saddr 35.235.240.0/20 tcp dport 22 accept comment "IAP SSH"