Skip to content

Commit fa0fe79

Browse files
committed
feat(agent): add api_key_scope to control agent token permissions
Change-Id: I90dd87756b47b589bf0a363e22de70d2cffd44fa Signed-off-by: Thomas Kosiewski <[email protected]>
1 parent 21147bf commit fa0fe79

File tree

8 files changed

+128
-13
lines changed

8 files changed

+128
-13
lines changed

.envrc

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
if ! has nix_direnv_version || ! nix_direnv_version 3.0.6; then
2+
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.6/direnvrc" "sha256-RYcUJaRMf8oF5LznDrlCXbkOQrywm0HDv1VjYGaJGdM="
3+
fi
4+
5+
nix_direnv_manual_reload
6+
7+
use flake .

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ website/vendor
3636

3737
# Binary
3838
terraform-provider-coder
39+
40+
# direnv
41+
.direnv

docs/resources/agent.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ data "coder_workspace" "me" {
1717
}
1818
1919
resource "coder_agent" "dev" {
20-
os = "linux"
21-
arch = "amd64"
22-
dir = "/workspace"
20+
os = "linux"
21+
arch = "amd64"
22+
dir = "/workspace"
23+
api_key_scope = "all"
2324
display_apps {
2425
vscode = true
2526
vscode_insiders = false
@@ -71,6 +72,7 @@ resource "kubernetes_pod" "dev" {
7172

7273
### Optional
7374

75+
- `api_key_scope` (String) Controls what API routes the agent token can access. Options: 'all' (full access) or 'no_user_data' (blocks /external-auth, /gitsshkey, and /gitauth routes)
7476
- `auth` (String) The authentication type the agent will use. Must be one of: `"token"`, `"google-instance-identity"`, `"aws-instance-identity"`, `"azure-instance-identity"`.
7577
- `connection_timeout` (Number) Time in seconds until the agent is marked as timed out when a connection with the server cannot be established. A value of zero never marks the agent as timed out.
7678
- `dir` (String) The starting directory when a user creates a shell session. Defaults to `"$HOME"`.

examples/resources/coder_agent/resource.tf

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ data "coder_workspace" "me" {
22
}
33

44
resource "coder_agent" "dev" {
5-
os = "linux"
6-
arch = "amd64"
7-
dir = "/workspace"
5+
os = "linux"
6+
arch = "amd64"
7+
dir = "/workspace"
8+
api_key_scope = "all"
89
display_apps {
910
vscode = true
1011
vscode_insiders = false

flake.lock

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
description = "Terraform provider for Coder";
33

44
inputs = {
5-
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
5+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
66
flake-utils.url = "github:numtide/flake-utils";
77
};
88

9-
outputs = { self, nixpkgs, flake-utils, ... }:
9+
outputs = { nixpkgs, flake-utils, ... }:
1010
flake-utils.lib.eachDefaultSystem (system:
1111
let
1212
pkgs = import nixpkgs {
@@ -21,7 +21,7 @@
2121
name = "devShell";
2222
buildInputs = with pkgs; [
2323
terraform
24-
go_1_20
24+
go_1_24
2525
];
2626
};
2727
}

provider/agent.go

+11
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ func agentResource() *schema.Resource {
8080
return nil
8181
},
8282
Schema: map[string]*schema.Schema{
83+
"api_key_scope": {
84+
Type: schema.TypeString,
85+
Optional: true,
86+
Default: "all",
87+
ForceNew: true,
88+
Description: "Controls what API routes the agent token can access. Options: 'all' (full access) or 'no_user_data' (blocks /external-auth, /gitsshkey, and /gitauth routes)",
89+
ValidateFunc: validation.StringInSlice([]string{
90+
"all",
91+
"no_user_data",
92+
}, false),
93+
},
8394
"init_script": {
8495
Type: schema.TypeString,
8596
Computed: true,

provider/agent_test.go

+91
Original file line numberDiff line numberDiff line change
@@ -709,5 +709,96 @@ func TestAgent_DisplayApps(t *testing.T) {
709709
}},
710710
})
711711
})
712+
}
713+
714+
// TestAgent_APIKeyScope tests valid states/transitions and invalid values for api_key_scope.
715+
func TestAgent_APIKeyScope(t *testing.T) {
716+
t.Parallel()
717+
718+
t.Run("ValidTransitions", func(t *testing.T) {
719+
t.Parallel()
720+
721+
resourceName := "coder_agent.test_scope_valid"
712722

723+
resource.Test(t, resource.TestCase{
724+
ProviderFactories: coderFactory(),
725+
IsUnitTest: true,
726+
Steps: []resource.TestStep{
727+
// Step 1: Default value
728+
{
729+
Config: `
730+
provider "coder" {
731+
url = "https://example.com"
732+
}
733+
resource "coder_agent" "test_scope_valid" {
734+
os = "linux"
735+
arch = "amd64"
736+
# api_key_scope is omitted, should default to "default"
737+
}
738+
`,
739+
Check: resource.ComposeTestCheckFunc(
740+
resource.TestCheckResourceAttr(resourceName, "api_key_scope", "all"),
741+
),
742+
},
743+
// Step 2: Explicit "default"
744+
{
745+
Config: `
746+
provider "coder" {
747+
url = "https://example.com"
748+
}
749+
resource "coder_agent" "test_scope_valid" {
750+
os = "linux"
751+
arch = "amd64"
752+
api_key_scope = "all"
753+
}
754+
`,
755+
Check: resource.ComposeTestCheckFunc(
756+
resource.TestCheckResourceAttr(resourceName, "api_key_scope", "all"),
757+
),
758+
},
759+
// Step 3: Explicit "no_user_data"
760+
{
761+
Config: `
762+
provider "coder" {
763+
url = "https://example.com"
764+
}
765+
resource "coder_agent" "test_scope_valid" {
766+
os = "linux"
767+
arch = "amd64"
768+
api_key_scope = "no_user_data"
769+
}
770+
`,
771+
Check: resource.ComposeTestCheckFunc(
772+
resource.TestCheckResourceAttr(resourceName, "api_key_scope", "no_user_data"),
773+
),
774+
},
775+
},
776+
})
777+
})
778+
779+
t.Run("InvalidValue", func(t *testing.T) {
780+
t.Parallel()
781+
782+
resource.Test(t, resource.TestCase{
783+
ProviderFactories: coderFactory(),
784+
IsUnitTest: true,
785+
Steps: []resource.TestStep{
786+
// Step 1: Invalid value check
787+
{
788+
Config: `
789+
provider "coder" {
790+
url = "https://example.com"
791+
}
792+
resource "coder_agent" "test_scope_invalid" { // Use unique name
793+
os = "linux"
794+
arch = "amd64"
795+
api_key_scope = "invalid-scope"
796+
}
797+
`,
798+
ExpectError: regexp.MustCompile(`expected api_key_scope to be one of \["all" "no_user_data"\], got invalid-scope`),
799+
PlanOnly: true,
800+
},
801+
},
802+
})
803+
})
713804
}

0 commit comments

Comments
 (0)