Files
cairnobs/terraform/main.go
T
jcoffey-dev 49dd050689 Start the Terraform provider: sentry_dashboard, the first resource
CLAUDE.md names the Terraform provider a first-class deliverable
alongside sentryctl ("CLI and Terraform provider are first-class, not
afterthoughts"), but no phase before this one had actually built any of
it -- no terraform/ directory existed. This is a first slice, not a
finished provider: one resource, scoped and confirmed with the project
owner before starting (a new pinned external dependency and an
architectural decision not covered in /docs/architecture.md are both
things CLAUDE.md's own "When in doubt" section says to ask about).

New Go module (terraform/, github.com/sentry/sentry/terraform) built on
HashiCorp's terraform-plugin-framework -- the actively-developed
library, not the legacy SDKv2, since there's no existing provider code
to migrate and no reason to start new on the framework HashiCorp itself
steers people away from.

internal/provider/client.go talks the exact same JSON contract
sentryctl's "dashboards apply" and web's Export JSON button already use
against api/dashboards.Handler (POST/GET/PUT/DELETE /dashboards[/{id}]) --
cli/README.md already named this "the seed of a future Terraform
provider: one JSON contract, multiple callers," this is that third
caller, not a new contract invented for Terraform's sake.

sentry_dashboard's schema deliberately leaves default_earliest/
default_latest Optional+Computed with no Terraform-side static default,
even though the API defaults them to "-1h"/"now" when empty -- letting
the API stay the one source of truth for what "unset" means rather than
duplicating that default in two places that could drift. tenant_id is
Computed-only, matching api/dashboards.Handler's own tenantID() doc
comment that a client-supplied value is always overridden server-side.

Panels are not modeled by this resource -- a genuinely separate resource
shape (own lifecycle, own endpoints, own validation needs), scoped out
deliberately, not an oversight. Alert rules, notification targets, and
tenant/RBAC resources are the same: real, disclosed future work, not
attempted in this pass. See terraform/README.md for the full accounting.

Verified: client_test.go runs real HTTP round trips against httptest.
Server (request construction, response parsing, the 404-vs-other-error
distinction Read/Delete need for Terraform's out-of-band-deletion
convention) -- same pattern cli/cmd/sentryctl's own tests already use
against the same api/dashboards endpoints. provider_test.go validates
both schemas are internally well-formed without needing a Terraform
binary. dashboard_resource_test.go's TestAccDashboardResource_basic is a
real acceptance test (terraform-plugin-testing), skip-gated by TF_ACC=1
per that framework's own convention -- even with TF_ACC set it would
still need a live api service (Postgres+ClickHouse) to apply against,
which this environment has no Docker access to bring up, so it has not
actually run here, same disclosed gap as every other live-infra test in
this repo.
2026-08-15 00:06:26 -07:00

51 lines
1.9 KiB
Go

// Command terraform-provider-sentry is Sentry's Terraform provider --
// CLAUDE.md names it a first-class deliverable alongside sentryctl
// ("CLI and Terraform provider are first-class, not afterthoughts"),
// but this is the first phase to actually build any of it.
//
// Scoped deliberately narrow to start: one resource
// (internal/provider.dashboardResource, sentry_dashboard), reusing the
// exact same JSON contract cli/cmd/sentryctl's "apply" subcommand and
// web's dashboard export button already use against
// api/dashboards.Handler -- "one JSON contract, multiple callers" is a
// design decision made back in Phase 3 (see cli/README.md), this
// provider is just a third caller of it, not a new contract. Alert
// rules, notification targets, and tenant/RBAC resources are real,
// disclosed future work, not attempted in this pass -- see README.md.
package main
import (
"context"
"flag"
"log"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/sentry/sentry/terraform/internal/provider"
)
// version is overridden at build time via -ldflags, same convention
// HashiCorp's own scaffold and every published provider use --
// Terraform's registry protocol reports this to users running
// `terraform version`. "dev" is deliberately obvious in output if
// someone runs a local build without setting it.
var version = "dev"
func main() {
var debug bool
flag.BoolVar(&debug, "debug", false, "run the provider with support for debuggers like delve")
flag.Parse()
err := providerserver.Serve(context.Background(), provider.New(version), providerserver.ServeOpts{
// Matches this provider's eventual Terraform Registry address --
// required by the protocol even before actual registry
// publication, since local dev overrides
// (~/.terraformrc dev_overrides) key on this same address.
Address: "registry.terraform.io/sentry/sentry",
Debug: debug,
})
if err != nil {
log.Fatal(err.Error())
}
}