Skip to content

Commit 4314f49

Browse files
committed
update validation schema to support tokens in instruqtTrack URLs
- Move tokens from config/base.json into sandbox.json instruqtTrack URLs - Remove token definitions from base configuration - Update sandbox configuration schema to validate tokens in URLs - Update lab configuration interface to remove separate token field - Simplify buildLabId to use complete instruqtTrack URL - Update documentation to reflect new configuration pattern - Remove separate token field from validateSandboxLab schema - Update instruqtTrack URL pattern validation to include token parameter - Align lab validation schema with unified token approach - Fix test cases to validate correct URL format This change completes the migration to embedding tokens directly in instruqtTrack URLs, ensuring consistent validation across the sandbox configuration.
1 parent 87df35c commit 4314f49

File tree

8 files changed

+90
-119
lines changed

8 files changed

+90
-119
lines changed

config/base.json

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,7 @@
3030
},
3131
"product_slugs_with_integrations": ["vault", "nomad", "packer"],
3232
"sandbox": {
33-
"instruqt_base_url": "https://play.instruqt.com/embed",
34-
"default_tokens": {
35-
"terraform-sandbox": "em_3vgTsBqCLq2blqtQ",
36-
"vault-sandbox": "em_CUFCBU0nSfCl2VHi",
37-
"boundary-sandbox": "em_YHsmJu4K1Wk3hwht",
38-
"consul-sandbox": "em_I5XI2XjO-ZMeH1_w",
39-
"consul-sandbox-sd": "em_MdAn4Od_foU6oybz",
40-
"nomad-sandbox": "em_0wOuIAyyjAQllLkc"
41-
}
33+
"instruqt_base_url": "https://play.instruqt.com/embed"
4234
}
4335
},
4436
"learn": {

src/content/sandbox/sandbox.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,31 @@
66
"description": "Get started quickly with Terraform. This sandbox includes Docker and LocalStack preinstalled to test your Terraform configuration.",
77
"products": ["terraform"],
88
"labId": "terraform-sandbox",
9-
"instruqtTrack": "hashicorp-learn/tracks/terraform-sandbox",
9+
"instruqtTrack": "hashicorp-learn/tracks/terraform-sandbox?token=em_3vgTsBqCLq2blqtQ",
1010
"documentation": "terraform.mdx"
1111
},
1212
{
1313
"title": "Vault Sandbox",
1414
"description": "Learn how to manage your secrets with Vault",
1515
"products": ["vault"],
1616
"labId": "vault-sandbox",
17-
"instruqtTrack": "hashicorp-learn/tracks/vault-sandbox",
17+
"instruqtTrack": "hashicorp-learn/tracks/vault-sandbox?token=em_CUFCBU0nSfCl2VHi",
1818
"documentation": "vault.mdx"
1919
},
2020
{
2121
"title": "Boundary Sandbox",
2222
"description": "Learn how to manage a Boundary cluster, configure and connect to targets, and set up target credentials.",
2323
"products": ["boundary"],
2424
"labId": "boundary-sandbox",
25-
"instruqtTrack": "hashicorp-learn/tracks/boundary-sandbox",
25+
"instruqtTrack": "hashicorp-learn/tracks/boundary-sandbox?token=em_YHsmJu4K1Wk3hwht",
2626
"documentation": "boundary.mdx"
2727
},
2828
{
2929
"title": "Consul Sandbox (Service discovery)",
3030
"description": "Learn about the process to register new services when you cannot run a client agent on a node, including how to manage access for external services using access control lists (ACLs).",
3131
"products": ["consul"],
3232
"labId": "consul-service-discovery-sandbox",
33-
"instruqtTrack": "hashicorp-learn/tracks/consul-sandbox-sd",
33+
"instruqtTrack": "hashicorp-learn/tracks/consul-sandbox-sd?token=em_MdAn4Od_foU6oybz",
3434
"scenario": "SD",
3535
"documentation": "consul-sd.mdx"
3636
},
@@ -39,16 +39,16 @@
3939
"description": "Learn about the process to register new services when you cannot run a client agent on a node, including how to manage access for external services using access control lists (ACLs).",
4040
"products": ["consul"],
4141
"labId": "consul-service-mesh-sandbox",
42-
"instruqtTrack": "hashicorp-learn/tracks/consul-sandbox",
42+
"instruqtTrack": "hashicorp-learn/tracks/consul-sandbox?token=em_I5XI2XjO-ZMeH1_w",
4343
"scenario": "SM",
4444
"documentation": "consul-sm.mdx"
4545
},
4646
{
4747
"title": "Nomad Sandbox",
48-
"description": "A Nomad cluster with three server nodes and one client node, Consul installed and configured, and Access Control Lists (ACLs) enabled for both Nomad and Consul.",
49-
"products": ["nomad", "consul", "vault"],
48+
"description": "Learn how to manage your infrastructure with Nomad",
49+
"products": ["nomad"],
5050
"labId": "nomad-sandbox",
51-
"instruqtTrack": "hashicorp-learn/tracks/nomad-sandbox",
51+
"instruqtTrack": "hashicorp-learn/tracks/nomad-sandbox?token=em_0wOuIAyyjAQllLkc",
5252
"documentation": "nomad.mdx"
5353
}
5454
]

src/contexts/instruqt-lab/__tests__/instruqt-lab.test.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,23 @@ vi.mock('content/sandbox/sandbox.json', () => ({
5858
description:
5959
'Test lab description that is long enough to pass validation',
6060
products: ['test-product'],
61-
instruqtTrack: 'hashicorp-learn/tracks/test-lab',
61+
instruqtTrack: 'hashicorp-learn/tracks/test-lab?token=em_test555',
6262
},
6363
{
6464
labId: 'test-product/stored-lab/stored-lab-id',
6565
title: 'Stored Lab',
6666
description:
6767
'Stored lab description that is long enough to pass validation',
6868
products: ['test-product'],
69-
instruqtTrack: 'hashicorp-learn/tracks/stored-lab',
69+
instruqtTrack: 'hashicorp-learn/tracks/stored-lab?token=em_test666',
7070
},
7171
{
7272
labId: 'test-product/close-test-lab/close-test-lab-id',
7373
title: 'Close Test Lab',
7474
description:
7575
'Close test lab description that is long enough to pass validation',
7676
products: ['test-product'],
77-
instruqtTrack: 'hashicorp-learn/tracks/close-test-lab',
77+
instruqtTrack: 'hashicorp-learn/tracks/close-test-lab?token=em_test777',
7878
},
7979
],
8080
},
@@ -123,23 +123,23 @@ function TestInstruqtProvider({ children }: { children: ReactNode }) {
123123
description:
124124
'Test lab description that is long enough to pass validation',
125125
products: ['test-product'],
126-
instruqtTrack: 'hashicorp-learn/tracks/test-lab',
126+
instruqtTrack: 'hashicorp-learn/tracks/test-lab?token=em_test555',
127127
},
128128
{
129129
labId: 'stored-lab-id',
130130
title: 'Stored Lab',
131131
description:
132132
'Stored lab description that is long enough to pass validation',
133133
products: ['test-product'],
134-
instruqtTrack: 'hashicorp-learn/tracks/stored-lab',
134+
instruqtTrack: 'hashicorp-learn/tracks/stored-lab?token=em_test666',
135135
},
136136
{
137137
labId: 'close-test-lab-id',
138138
title: 'Close Test Lab',
139139
description:
140140
'Close test lab description that is long enough to pass validation',
141141
products: ['test-product'],
142-
instruqtTrack: 'hashicorp-learn/tracks/close-test-lab',
142+
instruqtTrack: 'hashicorp-learn/tracks/close-test-lab?token=em_test777',
143143
},
144144
],
145145
}),

src/lib/__tests__/validate-sandbox-config.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,23 @@
55

66
import { validateSandboxConfigWithDetailedErrors, validateSandboxConfig, validateSandboxLab } from '../validate-sandbox-config'
77

8-
describe('validateSandboxConfig', () => {
9-
const validConfig = {
8+
describe('validateSandboxConfig', () => { const validConfig = {
109
products: ['terraform', 'vault'],
1110
labs: [
1211
{
1312
title: 'Terraform Sandbox',
1413
description: 'A comprehensive Terraform sandbox environment for learning',
1514
products: ['terraform'],
1615
labId: 'terraform-sandbox',
17-
instruqtTrack: 'hashicorp-learn/tracks/terraform-sandbox',
16+
instruqtTrack: 'hashicorp-learn/tracks/terraform-sandbox?token=em_test123',
1817
documentation: 'terraform.mdx'
1918
},
2019
{
2120
title: 'Vault Sandbox',
2221
description: 'Learn Vault secrets management',
2322
products: ['vault'],
2423
labId: 'vault-sandbox',
25-
instruqtTrack: 'hashicorp-learn/tracks/vault-sandbox'
24+
instruqtTrack: 'hashicorp-learn/tracks/vault-sandbox?token=em_test456'
2625
}
2726
]
2827
}
@@ -80,7 +79,7 @@ describe('validateSandboxConfig', () => {
8079
description: 'Test description that is long enough to pass validation',
8180
products: ['invalid-product'], // This product is not in the global products array
8281
labId: 'test-track-id',
83-
instruqtTrack: 'hashicorp-learn/tracks/test-track'
82+
instruqtTrack: 'hashicorp-learn/tracks/test-track?token=em_test789'
8483
}]
8584
}
8685
const result = validateSandboxConfigWithDetailedErrors(config)
@@ -99,14 +98,14 @@ describe('validateSandboxConfig', () => {
9998
description: 'Test description that is long enough',
10099
products: ['terraform'],
101100
labId: 'duplicate-track-id',
102-
instruqtTrack: 'hashicorp-learn/tracks/duplicate-track-1'
101+
instruqtTrack: 'hashicorp-learn/tracks/duplicate-track-1?token=em_test111'
103102
},
104103
{
105104
title: 'Test 2',
106105
description: 'Test description that is long enough',
107106
products: ['terraform'],
108107
labId: 'duplicate-track-id',
109-
instruqtTrack: 'hashicorp-learn/tracks/duplicate-track-2'
108+
instruqtTrack: 'hashicorp-learn/tracks/duplicate-track-2?token=em_test222'
110109
}
111110
]
112111
}
@@ -162,7 +161,8 @@ describe('validateSandboxConfig', () => {
162161
title: 'Test Lab',
163162
description: 'A test lab for validation',
164163
products: ['invalid-product'],
165-
labId: 'test/org/lab-id'
164+
labId: 'test-lab-id',
165+
instruqtTrack: 'hashicorp-learn/tracks/test-lab?token=em_test444'
166166
}
167167

168168
const result = validateSandboxLab(lab, availableProducts)
@@ -175,8 +175,8 @@ describe('validateSandboxConfig', () => {
175175
title: 'Valid Lab',
176176
description: 'A lab with valid products',
177177
products: ['terraform', 'vault'],
178-
labId: 'hashicorp/org/valid-lab',
179-
instruqtTrack: 'hashicorp/org/valid-lab'
178+
labId: 'valid-lab',
179+
instruqtTrack: 'hashicorp-learn/tracks/valid-lab?token=em_test333'
180180
}
181181

182182
const result = validateSandboxLab(lab, availableProducts)

src/lib/build-instruqt-url.ts

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,10 @@ const trackInstruqtUrlError = (
3939
}
4040
}
4141

42-
// Get default tokens from environment variables with fallbacks
43-
const getDefaultTokens = (): InstruqtTokens => ({
44-
'terraform-sandbox': 'em_3vgTsBqCLq2blqtQ',
45-
'vault-sandbox': 'em_CUFCBU0nSfCl2VHi',
46-
'boundary-sandbox': 'em_YHsmJu4K1Wk3hwht',
47-
'consul-sandbox-sd': 'em_MdAn4Od_foU6oybz',
48-
'consul-sandbox': 'em_I5XI2XjO-ZMeH1_w',
49-
'nomad-sandbox': 'em_0wOuIAyyjAQllLkc',
50-
})
51-
5242
/**
5343
* Builds the lab ID that will be used by the Instruqt embed
5444
* This combines the track path with query parameters
5545
* @param lab - The sandbox lab configuration (can be basic or full SandboxLab)
56-
* @param customTokens - Optional custom token mapping
5746
* @returns The complete lab ID for Instruqt embedding
5847
*/
5948
export function buildLabId(
@@ -65,9 +54,7 @@ export function buildLabId(
6554
trackInstruqtUrlError(
6655
'null_lab_config',
6756
'Lab configuration is null or undefined',
68-
{
69-
custom_tokens_provided: !!customTokens,
70-
}
57+
{ custom_tokens_provided: !!customTokens }
7158
)
7259
return ''
7360
}
@@ -79,32 +66,16 @@ export function buildLabId(
7966
{
8067
lab_id: lab.labId,
8168
lab_has_scenario: !!lab.scenario,
82-
custom_tokens_provided: !!customTokens,
8369
}
8470
)
8571
return lab.labId || ''
8672
}
8773

88-
const tokens = { ...getDefaultTokens(), ...customTokens }
89-
90-
// Build the track URL with parameters
9174
let labId = lab.instruqtTrack
9275

93-
// Add token parameter
94-
const trackName = lab.instruqtTrack.split('/').pop() || ''
95-
const token =
96-
process.env.INSTRUQT_TOKEN ||
97-
tokens[trackName] ||
98-
tokens[lab.labId] ||
99-
null
100-
101-
if (token) {
102-
labId += `?token=${token}`
103-
}
104-
10576
// Add scenario parameter if specified
10677
if (lab.scenario) {
107-
const separator = token ? '&' : '?'
78+
const separator = labId.includes('?') ? '&' : '?'
10879
labId += `${separator}rtp_SCENARIO=${lab.scenario}`
10980
}
11081

@@ -119,7 +90,6 @@ export function buildLabId(
11990
lab_id: lab?.labId,
12091
instruqt_track: lab?.instruqtTrack,
12192
has_scenario: !!lab?.scenario,
122-
custom_tokens_provided: !!customTokens,
12393
}
12494
)
12595
return lab?.labId || ''
@@ -128,7 +98,6 @@ export function buildLabId(
12898

12999
/**
130100
* Server-side function to build lab ID with config
131-
*
132101
*/
133102
export function buildLabIdWithConfig(lab: BasicLab | SandboxLab): string {
134103
try {
Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,52 @@
11
# Sandbox Authoring Guide
22

3-
This guide explains how to update HashiCorp sandbox configuration and tokens for the dev-portal project.
3+
This guide explains how to update HashiCorp sandbox configuration for the dev-portal project.
44

5-
## Where to Update Sandbox Track Paths and Scenarios
5+
## Where to Update Sandbox Configuration
66

7-
- Edit `src/content/sandbox/sandbox.json`
8-
- Update the `instruqtTrack` field for each sandbox to change the track path.
9-
- Update the `scenario` field if you need to change the scenario for a sandbox.
10-
- If you add a new sandbox, make sure to update both sandbox.json and `getDefaultTokens`.
7+
All sandbox configuration is managed in a single file: `src/content/sandbox/sandbox.json`
8+
9+
For each sandbox lab, you can configure:
10+
- The `instruqtTrack` field with both the track path and token
11+
- The `scenario` field if you need a specific scenario
1112

1213
Example:
1314

1415
```json
1516
{
16-
"labs": [
17-
{
18-
"title": "Terraform Sandbox",
19-
"instruqtTrack": "hashicorp-learn/tracks/terraform-sandbox",
20-
"scenario": "default"
21-
}
22-
// ...other labs
23-
]
17+
"labs": [
18+
{
19+
"title": "Terraform Sandbox",
20+
"description": "A comprehensive Terraform sandbox environment for learning",
21+
"products": ["terraform"],
22+
"labId": "terraform-sandbox",
23+
"instruqtTrack": "hashicorp-learn/tracks/terraform-sandbox?token=em_3vgTsBqCLq2blqtQ",
24+
"documentation": "terraform.mdx"
25+
},
26+
{
27+
"title": "Consul Sandbox (Service discovery)",
28+
"products": ["consul"],
29+
"labId": "consul-service-discovery-sandbox",
30+
"instruqtTrack": "hashicorp-learn/tracks/consul-sandbox-sd?token=em_MdAn4Od_foU6oybz",
31+
"scenario": "SD",
32+
"documentation": "consul-sd.mdx"
33+
}
34+
]
2435
}
2536
```
2637

27-
## Where to Update Sandbox Tokens
28-
29-
- Edit the `getDefaultTokens` function in `src/lib/build-instruqt-url.ts`
30-
- Tokens are public and scoped to each sandbox scenario. You can update them directly in this function.
38+
## Field Descriptions
3139

32-
Example:
33-
34-
```typescript
35-
const getDefaultTokens = (): InstruqtTokens => ({
36-
'terraform-sandbox': 'em_3vgTsBqCLq2blqtQ',
37-
// ...other tokens
38-
})
39-
```
40+
- `title`: Display name for the lab
41+
- `description`: Brief description of what the lab provides
42+
- `products`: Array of product slugs this lab supports (must be listed in the global products array)
43+
- `labId`: Unique identifier for the lab
44+
- `instruqtTrack`: Full Instruqt track path including the token (e.g., `hashicorp-learn/tracks/terraform-sandbox?token=em_xyz`)
45+
- `scenario`: (Optional) Specific scenario to load for this lab
46+
- `documentation`: (Optional) Path to MDX documentation file
4047

41-
## Summary
48+
## Notes
4249

43-
- Track paths and scenarios: `sandbox.json`
44-
- Tokens: `build-instruqt-url.ts`
50+
- Tokens are public and scoped to each sandbox scenario
51+
- Include the token directly in the `instruqtTrack` URL using the `?token=` parameter
52+
- If a scenario is specified, it will be automatically appended to the URL

0 commit comments

Comments
 (0)