A Pulumi provider for Devin, bridged from the official
CognitionAI/terraform-provider-devin
using the Pulumi Terraform Bridge.
Because it bridges the upstream Terraform provider directly, resources and data sources come from the same schema rather than a parallel reimplementation, so the two stay in lockstep as the upstream provider evolves.
npm install @pulumiverse/devin
pip install pulumiverse-devin
dotnet add package Pulumiverse.Devin
go get github.com/pulumiverse/pulumi-devin/sdkThe plugin binary is resolved from this repository's GitHub releases via the PluginDownloadURL
baked into the schema, so pulumi up fetches it with no extra configuration.
The provider is not in the Pulumi Registry, so a manual pulumi plugin install needs the server
spelled out. Installing the SDK is the normal path and needs none of this:
pulumi plugin install resource devin 0.1.0 --server github://api.github.com/pulumiversePrerequisites: Go 1.25+, pulumictl,
mise, the Pulumi CLI, Node.js, Yarn, Python 3, and the .NET SDK.
mise install # installs the toolchain, including the terraform converter
make tfgen # generate the Pulumi schema from the upstream Terraform provider
make provider # build bin/pulumi-resource-devin
make build_sdks # generate and build the dotnet, go, nodejs and python SDKsSchema generation runs the terraform converter, and the generated Makefile sets
PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION, so pulumi cannot fetch it on demand. The root
mise.toml declares it for that reason. Without it make tfgen fails with
no converter plugin 'pulumi-converter-terraform' found. See
pulumiverse/projen-pulumi-providers#8.
| Option | Environment variable | Notes |
|---|---|---|
apiUrl |
DEVIN_API_URL |
Devin API base URL; upstream default is https://api.devin.ai |
token |
DEVIN_TOKEN |
Enterprise or organization service user token (cog_ prefix); marked secret |
The bridge has to construct the upstream terraform-plugin-framework provider in-process to generate
its schema, but upstream's constructor lives in internal/provider and Go's module visibility rules
put it out of reach.
Until CognitionAI/terraform-provider-devin#3
lands, provider/shim supplies it: a module declaring the path
github.com/cognitionai/terraform-provider-devin/shim, which satisfies the internal-visibility check
because that path sits inside the upstream module's tree, wired in through a replace directive in
provider/go.mod.
When the upstream package is released, drop provider/shim and the replace, then bump the upstream
require. The import path in provider/resources.go is deliberately
identical either way, so nothing else changes.
All 18 resources and 6 data sources from the upstream provider are bridged and present in the generated schema, with descriptions for all 85 resource inputs.
| Layer | Coverage |
|---|---|
| Provider loads, configures and plans a resource | TestBasicTs / TestBasicPy, preview-only, in CI |
| Schema surface | schema-baseline.json drift guard |
| Docs edit rule | unit test in provider/resources_test.go |
| Create, update, delete against a real account | none |
There is no live create/update/delete coverage, and no realistic path to it. Every Devin API call
needs an enterprise or organization service user token, and most resources (Organization,
IpAccessList, IdpGroup, the *Role mappings) mutate real enterprise configuration, so there is no
free-tier or containerized equivalent of the throwaway server that bridged providers normally test
against. A token secret is also unavailable to pull requests from forks, so fork CI could not exercise
live resources even if one existed.
What is covered runs on every CI push and needs no credentials. TestBasicTs and TestBasicPy plan
a Playbook with SkipUpdate, so the programs are previewed and never applied. They prove the built
provider binary loads and serves, the generated schema is consumable by the Pulumi CLI, each SDK
constructs a resource, and provider configuration resolves from DEVIN_TOKEN / DEVIN_API_URL. That
last part is hand-written mapping in provider/resources.go rather than generated code, so it is worth
a test: deleting the token from the test environment makes both tests fail with Missing token.
Two details in previewOnly are deliberate. The token is fake, and DEVIN_API_URL points at a closed
port, so if a future change ever makes these tests reach the network they fail instead of touching a
real account. Note this is also why the examples create a resource rather than reading a data source:
a data source is invoked during preview and does call the API, so a getRoles example cannot be
tested without real credentials.
Contributions widening this are welcome.
schema-baseline.json is a committed snapshot of the generated schema, so an
upstream bump cannot change the public surface unnoticed. Upstream is pre-1.0 and moving fast, which is
exactly when that matters:
./scripts/check-schema-drift.sh # regenerates and diffs against the baselineReview any diff, then update the baseline deliberately in the same commit as the upstream bump.
Upstream descriptions name JSON members as bare snake_case (max_concurrent_runs). The docs parser
reads the inner underscores as markdown emphasis, which rendered as max*concurrent*runs in every
generated SDK. provider/resources.go adds a DocRules edit that
backticks bare identifiers before parsing, which both fixes the emphasis and lets the bridge translate
them to Pulumi names, so the same description now reads `maxConcurrentRuns`.
make tfgen converts 64 of 168 upstream HCL examples (38%). Two distinct causes, both outside this
repository:
- 10 examples fail to resolve the provider. Upstream's docs examples are bare resource snippets
with no
terraform { required_providers { ... } }block, so the converter assumesregistry.terraform.io/hashicorp/devinand drops the example. Injecting a provider block via aDocRulesedit would recover them, but the converter would then have to fetchcognitionai/devinfrom the Terraform Registry during codegen, making schema generation network-dependent and CI non-hermetic. Fixing it upstream (adding the block to the docs templates) is the better route. - The rest hit converter feature gaps.
one()is unimplemented (pulumi-converter-terraform#65) andforexpressions are unsupported in Go and YAML.
The failures are deterministic, giving the same 38% and the same 10 warnings on every run, cold cache or warm, so the schema baseline above is stable.
The upstream provider is pre-1.0 and moving quickly, so this provider tracks it on a 0.x line and
makes no Go module stability promise yet. The bare module path (sdk, not sdk/v2) is correct for
both 0.x and 1.x.
Apache-2.0. See LICENSE.