From 0938ce0e7fc8ae61a48c25a68e96a6ee085426f8 Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Mon, 2 Mar 2026 09:26:06 -0800 Subject: [PATCH 1/8] docs: expand SDK troubleshooting with runtime errors and platform-agnostic language Adds Token Expired, TDF Format Error, and Entity Resolution Failed sections to cover runtime errors not previously documented. Updates Permission Denied to mention 'key access denied'. Adds Getting Help section. Generalizes all opentdf-local-dev-specific URLs, Caddy/installer references, and hardcoded namespaces so the page can be imported into DSP docs without modification. Closes DSPX-2426 Co-Authored-By: Claude Sonnet 4.6 --- docs/sdks/troubleshooting.mdx | 154 ++++++++++++++++++++++++++-------- 1 file changed, 119 insertions(+), 35 deletions(-) diff --git a/docs/sdks/troubleshooting.mdx b/docs/sdks/troubleshooting.mdx index de1eb502..bb6636dc 100644 --- a/docs/sdks/troubleshooting.mdx +++ b/docs/sdks/troubleshooting.mdx @@ -11,46 +11,78 @@ import TabItem from '@theme/TabItem'; This guide covers common issues when working with the OpenTDF SDKs and how to resolve them. :::note Troubleshooting Scope -This section covers issues when **using the SDKs in your applications**. For platform installation and setup issues, see [Managing the Platform Troubleshooting](/getting-started/managing-platform#troubleshooting). +This section covers issues when **using the SDKs in your applications**. For platform installation and setup issues, refer to your platform's deployment documentation. ::: ## Authentication Failed **Error**: `rpc error: code = Unauthenticated` or `401 Unauthorized` -**Solution**: Verify your credentials are correct (replace `opentdf` with your client ID and `secret` with your client secret): +**Solution**: Verify your credentials are correct: ```bash -otdfctl auth client-credentials opentdf secret +otdfctl auth client-credentials ``` -Check that Keycloak is running: +Check that your identity provider is accessible: ```bash -curl https://keycloak.opentdf.local:9443/ +curl https:/// ``` +## Token Expired + +**Error**: `token expired`, `invalid token`, or `jwt expired` + +**Cause**: The authentication token's lifetime has been exceeded. OIDC tokens are short-lived by default. + +**Solution**: + +1. **Re-authenticate** (CLI): + ```bash + otdfctl auth client-credentials + ``` + +2. **Implement token refresh in your application**: The JavaScript SDK's `refreshAuthProvider` handles automatic token renewal: + ```js + import { AuthProviders } from '@opentdf/client'; + + const authProvider = AuthProviders.refreshAuthProvider({ + clientId: 'your-client-id', + exchange: 'client_credentials', + clientSecret: 'your-client-secret', + oidcOrigin: 'https:///realms/', + }); + ``` + +3. **Re-instantiate the SDK**: For Go and Java, create a new SDK instance with fresh credentials when a token error occurs. + ## Certificate Errors (SSL/TLS) **Error**: `x509: certificate signed by unknown authority` or `Failed to validate TLS certificates` -**Cause**: The platform uses self-signed certificates for local development. During installation, the [setup script](/quickstart#step-2-install-opentdf) automatically imports the Caddy root CA certificate to your system keychain. +**Cause**: The platform is using a self-signed or privately-issued certificate that your system doesn't trust. -**Solution**: If you're seeing certificate errors, the certificate import may have failed during installation. Try these steps: +**Solution**: -1. **Restart your browser and terminal** - The certificate import requires applications to reload their certificate stores. Close and reopen your browser and terminal windows. +1. **Restart your browser and terminal** after trusting a new certificate — applications must reload their certificate stores to pick up the change. -2. **Verify the certificate was imported** - During the [installation process](/quickstart#step-2-install-opentdf), you should have been prompted twice for your password: - - Once to add entries to /etc/hosts - - Once to import the SSL certificate +2. **Trust the platform's CA certificate** on your system: - If you don't remember seeing both prompts, the certificate import may have failed. + ```bash + # macOS + sudo security add-trusted-cert -d -r trustRoot \ + -k /Library/Keychains/System.keychain ca-cert.pem + + # Linux + sudo cp ca-cert.pem /usr/local/share/ca-certificates/platform-ca.crt + sudo update-ca-certificates + ``` -3. **Skip certificate verification** (quick workaround for CLI): + Obtain the CA certificate from your platform administrator or deployment documentation. + +3. **Skip certificate verification** (quick workaround for CLI only, not recommended for production): ```bash export OTDFCTL_TLS_NO_VERIFY=true ``` - This allows `otdfctl` commands to work without validating certificates. - -4. **Manually trust the certificate** - For SDKs and applications, you'll need to properly trust the certificate. See the [TLS Certificate Verification](/getting-started/managing-platform#tls-certificate-verification) guide for detailed steps on extracting and trusting the Caddy root CA certificate on macOS, Linux, or Windows. ## Connection Refused @@ -58,16 +90,12 @@ curl https://keycloak.opentdf.local:9443/ **Solution**: Verify your platform is running: ```bash -curl https://platform.opentdf.local:8443/healthz +curl https:///healthz ``` Should return: `{"status":"SERVING"}` -If not running, restart the platform: -```bash -cd ~/.opentdf/platform -docker compose up -d -``` +If not running, restart your platform services according to your deployment documentation. ## Import Errors @@ -95,8 +123,8 @@ npm install @opentdf/client ``` -reader.WriteTo failed: splitKey.unable to reconstruct split key: map[{https://platform.opentdf.local:8443 }:tdf: rewrap request 403 -kao unwrap failed for split {https://platform.opentdf.local:8443 }: permission_denied: request error +reader.WriteTo failed: splitKey.unable to reconstruct split key: map[{https:// }:tdf: rewrap request 403 +kao unwrap failed for split {https:// }: permission_denied: request error rpc error: code = PermissionDenied desc = forbidden] ``` @@ -110,7 +138,7 @@ rpc error: code = PermissionDenied desc = forbidden] ``` io.opentdf.platform.sdk.SDK$SplitKeyException: splitKey.unable to reconstruct split key: -{KeySplitStep{kas='https://platform.opentdf.local:8443/kas', splitID=''}=io.opentdf.platform.sdk.SDKException: error unwrapping key} +{KeySplitStep{kas='https:///kas', splitID=''}=io.opentdf.platform.sdk.SDKException: error unwrapping key} error unwrapping key ``` @@ -134,11 +162,11 @@ error unwrapping key -These errors indicate an authorization failure, not a cryptographic or network issue. +These errors indicate an authorization failure, not a cryptographic or network issue. You may also see `key access denied` from the KAS directly. **Cause**: Your identity lacks the required entitlements (attribute values) to decrypt the TDF. This is ABAC (Attribute-Based Access Control) working correctly. -For example, if you encrypted data with `https://opentdf.io/attr/department/value/marketing`, you need a subject mapping that grants you the `marketing` entitlement. +For example, if you encrypted data with `https://example.com/attr/department/value/marketing`, you need a subject mapping that grants you the `marketing` entitlement. **Solution**: Grant yourself (or the entity) entitlements by [creating a subject mapping](/sdks/policy#create-subject-mapping). @@ -146,22 +174,61 @@ For example, if you encrypted data with `https://opentdf.io/attr/department/valu ```bash # List your attributes to get the attribute value ID -otdfctl policy attributes list --namespace opentdf.io +otdfctl policy attributes list --namespace # Create a subject condition set (if needed) otdfctl policy subject-condition-sets create \ - --subject-set '[".clientId == \"opentdf\""]' \ - --label "OpenTDF Service Account" + --subject-set '[".clientId == \"\""]' \ + --label "My Service Account" export SUBJECT_CONDITION_SET_ID= # Create the subject mapping to grant the entitlement otdfctl policy subject-mappings create \ --action read \ - --attribute-value-fqn https://opentdf.io/attr/department/value/marketing \ + --attribute-value-fqn https://example.com/attr/department/value/marketing \ --subject-condition-set-id $SUBJECT_CONDITION_SET_ID ``` +## TDF Format Error + +**Error**: `invalid TDF format`, `malformed TDF`, or `tamper detected` + +**Cause**: The file was corrupted during transfer, modified after encryption, or was created with an incompatible TDF version. + +**Solution**: + +1. **Re-encrypt the original file** — if you have access to the plaintext, create a fresh TDF +2. **Check SDK version compatibility** — the SDK used to decrypt must support the TDF format version used to encrypt (e.g., TDF3 vs nanoTDF) +3. **Verify file integrity** — TDFs are tamper-evident; any modification after encryption will cause decryption to fail +4. **Check file transfer** — binary TDF files can be corrupted by text-mode transfers; ensure files are transferred in binary mode + +## Entity Resolution Failed + +**Error**: `entity resolution failed` or `failed to resolve entity` + +**Cause**: The platform cannot map your identity (from the OIDC token) to an entity with attributes. This happens when subject mappings are not configured for your identity provider claims. + +**Solution**: Create a subject mapping that connects your IdP identity to the appropriate attribute entitlements: + +```bash +# Create a subject condition set matching your identity +# (replace the selector with the claim from your OIDC token, e.g. clientId, email, group) +otdfctl policy subject-condition-sets create \ + --subject-set '[".clientId == \"your-client-id\""]' \ + --label "Your App Service Account" + +export SCS_ID= + +# Map the condition set to an attribute value +otdfctl policy subject-mappings create \ + --action read \ + --attribute-value-fqn https://example.com/attr/department/value/engineering \ + --subject-condition-set-id $SCS_ID +``` + +For more detail on configuring subject mappings, see [Policy Management](/sdks/policy#create-subject-mapping). + ## Resource Already Exists **Error**: `already_exists: resource unique field violation` @@ -216,8 +283,7 @@ exit status 1 **Quick fix using the CLI:** ```bash -# Get the namespace ID for opentdf.io -# (Namespace should exist from platform initialization - see /quickstart) +# Get the namespace ID (replace 'example.com' with your namespace) export NAMESPACE_ID=$(otdfctl policy attributes list --json | jq -r '.attributes[0].namespace.id // empty') # Create the attribute definition with initial values @@ -233,9 +299,27 @@ otdfctl policy attributes create \ Alternatively, to add values after creating the attribute: ```bash -# Get the attribute ID for 'department' in the 'opentdf.io' namespace -export DEPT_ATTRIBUTE_ID=$(otdfctl policy attributes list --json | jq -r '[.attributes[] | select(.name=="department" and .namespace.name=="opentdf.io")][0].id') +# Get the attribute ID for 'department' in your namespace +export DEPT_ATTRIBUTE_ID=$(otdfctl policy attributes list --json | jq -r '[.attributes[] | select(.name=="department" and .namespace.name=="")][0].id') # Add individual value(s) otdfctl policy attributes values create --attribute-id $DEPT_ATTRIBUTE_ID --value marketing ``` + +## Getting Help + +If you can't resolve an issue using this guide, here are the next steps: + +1. **Check platform health first**: + ```bash + curl https:///healthz + ``` + Should return `{"status":"SERVING"}`. If not, refer to your platform's deployment documentation. + +2. **Search existing GitHub Discussions** — many common questions are already answered in the [opentdf/platform discussions](https://github.com/opentdf/platform/discussions). + +3. **Open a GitHub issue** with: + - SDK language and version + - Full error message (including stack trace if available) + - Minimal code that reproduces the issue + - Platform version and how it's deployed From c8b49716addb0cb4df76b4bd2e6e001751648e78 Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Mon, 2 Mar 2026 09:58:20 -0800 Subject: [PATCH 2/8] add preview steps to agents and claude Signed-off-by: Mary Dickson --- AGENTS.md | 13 +++++++++++++ CLAUDE.md | 1 + 2 files changed, 14 insertions(+) create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md index 22e7f204..e705e637 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,6 +33,19 @@ Docs-only checks: - There is no dedicated unit test runner; CI primarily validates `npm run build` and Vale. - If you touch `docs/getting-started/` Docker Compose instructions, sanity-check them locally when feasible. +## Preview Deployment + +After opening a PR, deploy a Surge preview so reviewers can see the changes live. Use the ticket number as the identifier. + +```bash +npm run build +npx surge build opentdf-docs-preview-.surge.sh +``` + +Preview URL: `https://opentdf-docs-preview-.surge.sh/` + +A free Surge account is required — first run will prompt to sign up or log in. + ## Commit & Pull Request Guidelines - Commits follow Conventional Commits as seen in history: `feat(docs): …`, `fix(docs): …`, `chore(deps): …`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..962a3e8f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +Read AGENTS.md for project guidelines. From ab69b9f5303f31e55994e33a74c1e11a28f5aacd Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Mon, 2 Mar 2026 10:10:19 -0800 Subject: [PATCH 3/8] fix(ci): prevent GitHub API rate limit crashes in check-vendored-yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without authentication, the GitHub API caps at 60 req/hr per IP. When exceeded it returns {"message": "API rate limit exceeded"} ��� not an array — causing "contents is not iterable" and a build failure. - Add githubHeaders() to send GITHUB_TOKEN when available (5000 req/hr) - Add Array.isArray guard so rate-limit responses warn and skip instead of crash - Add HTTP error handling in fetchJson/fetchText for 4xx/5xx responses - Pass GITHUB_TOKEN to the build step in test-deploy.yaml - Remove duplicate *.info.mdx files instead of silently skipping rename Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/test-deploy.yaml | 2 ++ src/openapi/check-vendored-yaml.ts | 32 +++++++++++++++++++++++++++--- src/openapi/preprocessing.ts | 7 +++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-deploy.yaml b/.github/workflows/test-deploy.yaml index ba63a0ed..2e95bed9 100644 --- a/.github/workflows/test-deploy.yaml +++ b/.github/workflows/test-deploy.yaml @@ -24,3 +24,5 @@ jobs: run: npm ci - name: Test build website run: npm run build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/src/openapi/check-vendored-yaml.ts b/src/openapi/check-vendored-yaml.ts index 285f21fd..56a97808 100644 --- a/src/openapi/check-vendored-yaml.ts +++ b/src/openapi/check-vendored-yaml.ts @@ -9,6 +9,17 @@ import { openApiSpecsArray } from './preprocessing'; const PLATFORM_API_BASE = 'https://api.github.com/repos/opentdf/platform'; const PLATFORM_RAW_BASE = 'https://raw.githubusercontent.com/opentdf/platform/refs/heads/main'; +function githubHeaders(): Record { + const headers: Record = { + 'User-Agent': 'opentdf-docs-check-vendored-yaml', + 'Accept': 'application/vnd.github+json', + }; + if (process.env.GITHUB_TOKEN) { + headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`; + } + return headers; +} + function fileHash(filePath: string): string { if (!fs.existsSync(filePath)) return ''; const data = fs.readFileSync(filePath); @@ -39,10 +50,14 @@ function downloadFile(url: string, dest: string): Promise { function fetchJson(url: string): Promise { return new Promise((resolve, reject) => { import('https').then(https => { - https.get(url, { headers: { 'User-Agent': 'opentdf-docs-check-vendored-yaml' } } as any, (response: any) => { + https.get(url, { headers: githubHeaders() } as any, (response: any) => { let data = ''; response.on('data', (chunk: string) => { data += chunk; }); response.on('end', () => { + if (response.statusCode && response.statusCode >= 400) { + reject(new Error(`GitHub API request failed (${response.statusCode}) for ${url}: ${data}`)); + return; + } try { resolve(JSON.parse(data)); } catch (e) { reject(new Error(`Failed to parse JSON from ${url}: ${e}`)); } }); @@ -54,10 +69,16 @@ function fetchJson(url: string): Promise { function fetchText(url: string): Promise { return new Promise((resolve, reject) => { import('https').then(https => { - https.get(url, { headers: { 'User-Agent': 'opentdf-docs-check-vendored-yaml' } } as any, (response: any) => { + https.get(url, { headers: githubHeaders() } as any, (response: any) => { let data = ''; response.on('data', (chunk: string) => { data += chunk; }); - response.on('end', () => resolve(data)); + response.on('end', () => { + if (response.statusCode && response.statusCode >= 400) { + reject(new Error(`Failed to fetch text from ${url} (${response.statusCode}): ${data}`)); + return; + } + resolve(data); + }); }).on('error', reject); }).catch(reject); }); @@ -69,6 +90,11 @@ function fetchText(url: string): Promise { async function fetchRemoteSpecPaths(dirPath = 'docs/openapi'): Promise { const specPaths: string[] = []; const contents = await fetchJson(`${PLATFORM_API_BASE}/contents/${dirPath}`); + if (!Array.isArray(contents)) { + const message = typeof contents?.message === 'string' ? contents.message : JSON.stringify(contents); + console.warn(`⚠️ Unexpected GitHub API response for ${dirPath}; skipping unregistered spec scan. Response: ${message}`); + return specPaths; + } for (const item of contents) { if (item.type === 'file' && item.name.endsWith('.yaml')) { diff --git a/src/openapi/preprocessing.ts b/src/openapi/preprocessing.ts index 02fd8f20..5b05a2f0 100644 --- a/src/openapi/preprocessing.ts +++ b/src/openapi/preprocessing.ts @@ -467,7 +467,10 @@ function renameInfoFilesToIndex() { } else if (item.name.endsWith('.info.mdx')) { const newPath = path.join(dir, 'index.mdx'); if (fs.existsSync(newPath)) { - console.warn(`⚠️ Skipping rename of ${fullPath} because destination ${newPath} already exists.`); + // Keep index.mdx as the canonical category index and remove stale + // *.info.mdx duplicates that can conflict with sidebar category routing. + fs.unlinkSync(fullPath); + console.log(` Removed duplicate info file: ${fullPath}`); } else { fs.renameSync(fullPath, newPath); console.log(` Renamed: ${fullPath} → ${newPath}`); @@ -582,4 +585,4 @@ Most endpoints require authentication. Configure your access token in the API do } // Export the function and data without automatically executing it -export { openApiSpecs, openApiSpecsArray, preprocessOpenApiSpecs, updateOpenApiIndex, renameInfoFilesToIndex }; \ No newline at end of file +export { openApiSpecs, openApiSpecsArray, preprocessOpenApiSpecs, updateOpenApiIndex, renameInfoFilesToIndex }; From 90c7df61632bcae63fa3438ec82fb54194b07a23 Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Mon, 2 Mar 2026 10:42:26 -0800 Subject: [PATCH 4/8] fix(docs): address code review feedback on DSPX-2426 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 'attribute does not exist' error to Resource Not Found section (ticket error #9 was missing coverage) - Fix Keycloak-specific /realms/ path in Token Expired JS example with a comment to adjust for other IdPs - Fix placeholder inconsistency: 'your-client-id' → '' in Entity Resolution Failed section - Restore internal link in scope note as full URL so it works when imported into DSP docs - Add Windows PowerShell cert trust instructions to Certificate Errors - Replace duplicate health check code block in Getting Help with a prose reference to the Connection Refused section - Improve preprocessing.ts log message: 'stale duplicate' is clearer Co-Authored-By: Claude Sonnet 4.6 --- docs/sdks/troubleshooting.mdx | 21 +++++++++++---------- src/openapi/preprocessing.ts | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/docs/sdks/troubleshooting.mdx b/docs/sdks/troubleshooting.mdx index bb6636dc..f1ce5aeb 100644 --- a/docs/sdks/troubleshooting.mdx +++ b/docs/sdks/troubleshooting.mdx @@ -11,7 +11,7 @@ import TabItem from '@theme/TabItem'; This guide covers common issues when working with the OpenTDF SDKs and how to resolve them. :::note Troubleshooting Scope -This section covers issues when **using the SDKs in your applications**. For platform installation and setup issues, refer to your platform's deployment documentation. +This section covers issues when **using the SDKs in your applications**. For platform installation and setup issues, see [docs.opentdf.io — Managing the Platform](https://docs.opentdf.io/getting-started/managing-platform#troubleshooting) or your platform's deployment documentation. ::: ## Authentication Failed @@ -49,7 +49,7 @@ curl https:/// clientId: 'your-client-id', exchange: 'client_credentials', clientSecret: 'your-client-secret', - oidcOrigin: 'https:///realms/', + oidcOrigin: 'https://', // Keycloak: append /realms/; adjust path for your IdP }); ``` @@ -77,6 +77,11 @@ curl https:/// sudo update-ca-certificates ``` + ```powershell + # Windows (PowerShell as Administrator) + Import-Certificate -FilePath ca-cert.pem -CertStoreLocation Cert:\LocalMachine\Root + ``` + Obtain the CA certificate from your platform administrator or deployment documentation. 3. **Skip certificate verification** (quick workaround for CLI only, not recommended for production): @@ -215,7 +220,7 @@ otdfctl policy subject-mappings create \ # Create a subject condition set matching your identity # (replace the selector with the claim from your OIDC token, e.g. clientId, email, group) otdfctl policy subject-condition-sets create \ - --subject-set '[".clientId == \"your-client-id\""]' \ + --subject-set '[".clientId == \"\""]' \ --label "Your App Service Account" export SCS_ID= @@ -268,9 +273,9 @@ exit status 1 ## Resource Not Found -**Error**: `not_found: resource not found` or `attribute not found` +**Error**: `not_found: resource not found`, `attribute not found`, or `attribute does not exist` -**Cause**: You're trying to use a resource (namespace, attribute, or attribute value) that doesn't exist on the platform. +**Cause**: You're trying to use a resource (namespace, attribute, or attribute value) that doesn't exist on the platform. This commonly happens when an attribute FQN is passed to `CreateTDF` before the attribute has been created. **Prevention**: Use [`ValidateAttributes`](/sdks/discovery#validateattributes) before calling `CreateTDF` to catch missing attributes immediately instead of at decryption time. Available in all three SDKs: @@ -310,11 +315,7 @@ otdfctl policy attributes values create --attribute-id $DEPT_ATTRIBUTE_ID --valu If you can't resolve an issue using this guide, here are the next steps: -1. **Check platform health first**: - ```bash - curl https:///healthz - ``` - Should return `{"status":"SERVING"}`. If not, refer to your platform's deployment documentation. +1. **Check platform health** — verify the platform is reachable and serving (see [Connection Refused](#connection-refused) above). If the platform is down, resolve that first. 2. **Search existing GitHub Discussions** — many common questions are already answered in the [opentdf/platform discussions](https://github.com/opentdf/platform/discussions). diff --git a/src/openapi/preprocessing.ts b/src/openapi/preprocessing.ts index 5b05a2f0..0d3cd570 100644 --- a/src/openapi/preprocessing.ts +++ b/src/openapi/preprocessing.ts @@ -470,7 +470,7 @@ function renameInfoFilesToIndex() { // Keep index.mdx as the canonical category index and remove stale // *.info.mdx duplicates that can conflict with sidebar category routing. fs.unlinkSync(fullPath); - console.log(` Removed duplicate info file: ${fullPath}`); + console.log(` Removed stale duplicate (index.mdx already exists): ${fullPath}`); } else { fs.renameSync(fullPath, newPath); console.log(` Renamed: ${fullPath} → ${newPath}`); From 76b8200071812ec4077a7b2a44092e5d4abaa200 Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Mon, 2 Mar 2026 11:40:26 -0800 Subject: [PATCH 5/8] fix(troubleshooting): use --attribute-value-id for tructl compatibility Replace --attribute-value-fqn with a jq lookup + --attribute-value-id in the Permission Denied and Entity Resolution Failed CLI examples. Both otdfctl and tructl support --attribute-value-id; tructl has no --attribute-value-fqn flag (tracked in DSPX-2529), so this approach works with both CLIs and removes the need for a special-case transform when importing into DSP docs. Also removes --namespace from the attributes list call; tructl has no --namespace filter flag (also tracked in DSPX-2529). Co-Authored-By: Claude Sonnet 4.6 --- docs/sdks/troubleshooting.mdx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/sdks/troubleshooting.mdx b/docs/sdks/troubleshooting.mdx index f1ce5aeb..937269e1 100644 --- a/docs/sdks/troubleshooting.mdx +++ b/docs/sdks/troubleshooting.mdx @@ -178,8 +178,9 @@ For example, if you encrypted data with `https://example.com/attr/department/val **Quick fix using the CLI:** ```bash -# List your attributes to get the attribute value ID -otdfctl policy attributes list --namespace +# Get the ID of the attribute value you want to grant +export ATTRIBUTE_VALUE_ID=$(otdfctl policy attributes list --json | \ + jq -r '[.attributes[] | select(.name=="department") | .values[] | select(.value=="marketing")][0].id') # Create a subject condition set (if needed) otdfctl policy subject-condition-sets create \ @@ -191,7 +192,7 @@ export SUBJECT_CONDITION_SET_ID= # Create the subject mapping to grant the entitlement otdfctl policy subject-mappings create \ --action read \ - --attribute-value-fqn https://example.com/attr/department/value/marketing \ + --attribute-value-id $ATTRIBUTE_VALUE_ID \ --subject-condition-set-id $SUBJECT_CONDITION_SET_ID ``` @@ -225,10 +226,14 @@ otdfctl policy subject-condition-sets create \ export SCS_ID= -# Map the condition set to an attribute value +# Get the ID of the attribute value to grant +export ATTRIBUTE_VALUE_ID=$(otdfctl policy attributes list --json | \ + jq -r '[.attributes[] | select(.name=="department") | .values[] | select(.value=="engineering")][0].id') + +# Map the condition set to the attribute value otdfctl policy subject-mappings create \ --action read \ - --attribute-value-fqn https://example.com/attr/department/value/engineering \ + --attribute-value-id $ATTRIBUTE_VALUE_ID \ --subject-condition-set-id $SCS_ID ``` From 9e0ecb73d82e19fe117e237c1288622c86c9a5e4 Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Mon, 2 Mar 2026 12:38:16 -0800 Subject: [PATCH 6/8] =?UTF-8?q?fix(docs):=20reorder=20cert=20trust=20steps?= =?UTF-8?q?=20=E2=80=94=20import=20before=20restart?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- docs/sdks/troubleshooting.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sdks/troubleshooting.mdx b/docs/sdks/troubleshooting.mdx index 937269e1..c5dcda17 100644 --- a/docs/sdks/troubleshooting.mdx +++ b/docs/sdks/troubleshooting.mdx @@ -63,9 +63,7 @@ curl https:/// **Solution**: -1. **Restart your browser and terminal** after trusting a new certificate — applications must reload their certificate stores to pick up the change. - -2. **Trust the platform's CA certificate** on your system: +1. **Trust the platform's CA certificate** on your system: ```bash # macOS @@ -84,6 +82,8 @@ curl https:/// Obtain the CA certificate from your platform administrator or deployment documentation. +2. **Restart your browser and terminal** after trusting the certificate — applications must reload their certificate stores to pick up the change. + 3. **Skip certificate verification** (quick workaround for CLI only, not recommended for production): ```bash export OTDFCTL_TLS_NO_VERIFY=true From 01306f9011b3ba9fc3cb999a00d9c3e296c9f1d6 Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Tue, 3 Mar 2026 07:46:27 -0800 Subject: [PATCH 7/8] chore: revert check-vendored-yaml.ts to match main Co-Authored-By: Claude Sonnet 4.6 --- src/openapi/check-vendored-yaml.ts | 32 +++--------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/src/openapi/check-vendored-yaml.ts b/src/openapi/check-vendored-yaml.ts index 56a97808..285f21fd 100644 --- a/src/openapi/check-vendored-yaml.ts +++ b/src/openapi/check-vendored-yaml.ts @@ -9,17 +9,6 @@ import { openApiSpecsArray } from './preprocessing'; const PLATFORM_API_BASE = 'https://api.github.com/repos/opentdf/platform'; const PLATFORM_RAW_BASE = 'https://raw.githubusercontent.com/opentdf/platform/refs/heads/main'; -function githubHeaders(): Record { - const headers: Record = { - 'User-Agent': 'opentdf-docs-check-vendored-yaml', - 'Accept': 'application/vnd.github+json', - }; - if (process.env.GITHUB_TOKEN) { - headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`; - } - return headers; -} - function fileHash(filePath: string): string { if (!fs.existsSync(filePath)) return ''; const data = fs.readFileSync(filePath); @@ -50,14 +39,10 @@ function downloadFile(url: string, dest: string): Promise { function fetchJson(url: string): Promise { return new Promise((resolve, reject) => { import('https').then(https => { - https.get(url, { headers: githubHeaders() } as any, (response: any) => { + https.get(url, { headers: { 'User-Agent': 'opentdf-docs-check-vendored-yaml' } } as any, (response: any) => { let data = ''; response.on('data', (chunk: string) => { data += chunk; }); response.on('end', () => { - if (response.statusCode && response.statusCode >= 400) { - reject(new Error(`GitHub API request failed (${response.statusCode}) for ${url}: ${data}`)); - return; - } try { resolve(JSON.parse(data)); } catch (e) { reject(new Error(`Failed to parse JSON from ${url}: ${e}`)); } }); @@ -69,16 +54,10 @@ function fetchJson(url: string): Promise { function fetchText(url: string): Promise { return new Promise((resolve, reject) => { import('https').then(https => { - https.get(url, { headers: githubHeaders() } as any, (response: any) => { + https.get(url, { headers: { 'User-Agent': 'opentdf-docs-check-vendored-yaml' } } as any, (response: any) => { let data = ''; response.on('data', (chunk: string) => { data += chunk; }); - response.on('end', () => { - if (response.statusCode && response.statusCode >= 400) { - reject(new Error(`Failed to fetch text from ${url} (${response.statusCode}): ${data}`)); - return; - } - resolve(data); - }); + response.on('end', () => resolve(data)); }).on('error', reject); }).catch(reject); }); @@ -90,11 +69,6 @@ function fetchText(url: string): Promise { async function fetchRemoteSpecPaths(dirPath = 'docs/openapi'): Promise { const specPaths: string[] = []; const contents = await fetchJson(`${PLATFORM_API_BASE}/contents/${dirPath}`); - if (!Array.isArray(contents)) { - const message = typeof contents?.message === 'string' ? contents.message : JSON.stringify(contents); - console.warn(`⚠️ Unexpected GitHub API response for ${dirPath}; skipping unregistered spec scan. Response: ${message}`); - return specPaths; - } for (const item of contents) { if (item.type === 'file' && item.name.endsWith('.yaml')) { From f5ab04fcaf534c27eeaeea2dba0221b6097cf7ce Mon Sep 17 00:00:00 2001 From: Mary Dickson Date: Tue, 3 Mar 2026 07:46:34 -0800 Subject: [PATCH 8/8] chore: revert preprocessing.ts to match main Co-Authored-By: Claude Sonnet 4.6 --- src/openapi/preprocessing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openapi/preprocessing.ts b/src/openapi/preprocessing.ts index 94986983..fdfb2ee7 100644 --- a/src/openapi/preprocessing.ts +++ b/src/openapi/preprocessing.ts @@ -586,4 +586,4 @@ Most endpoints require authentication. Configure your access token in the API do } // Export the function and data without automatically executing it -export { openApiSpecs, openApiSpecsArray, preprocessOpenApiSpecs, updateOpenApiIndex, renameInfoFilesToIndex }; +export { openApiSpecs, openApiSpecsArray, preprocessOpenApiSpecs, updateOpenApiIndex, renameInfoFilesToIndex }; \ No newline at end of file