Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,13 @@ const config: Config = {
},
],
copyright: `
<span>Copyright © ${new Date().getFullYear()} OpenTDF</span>
<iconify-icon data-icon="mdi:shield-check" style="color: #00FF00;"></iconify-icon>
<div>
<span>Copyright © ${new Date().getFullYear()} OpenTDF</span>
</div>
<div class="footer__license-info">
Documentation licensed under <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noopener noreferrer">CC BY 4.0</a> •
Code licensed under <a href="https://github.com/opentdf/platform/blob/main/LICENSE" target="_blank" rel="noopener noreferrer">BSD 3-Clause</a>
</div>
`,
},
prism: {
Expand Down
22 changes: 22 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
"gen-api-docs-all": "docusaurus gen-api-docs all --all-versions",
"gen-api-docs-all": "docusaurus gen-api-docs all --all-versions && npm run update-openapi-index",
"gen-api-docs-clean": "docusaurus clean-api-docs all",
"update-openapi-index": "tsx scripts/update-openapi-index.ts",
"check-vendored-yaml": "tsx src/openapi/check-vendored-yaml.ts",
"update-vendored-yaml": "tsx src/openapi/update-vendored-yaml.ts"
},
Expand Down
16 changes: 16 additions & 0 deletions scripts/update-openapi-index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Post-processing script to update the OpenAPI index page with correct links
* after the OpenAPI docs have been generated.
*/

import { updateOpenApiIndex, renameInfoFilesToIndex } from '../src/openapi/preprocessing';

try {
console.log('🔄 Running post-generation OpenAPI processing...');
renameInfoFilesToIndex();
updateOpenApiIndex();
console.log('✅ OpenAPI post-processing complete');
} catch (error) {
console.error('❌ OpenAPI post-processing failed:', error);
process.exit(1);
}
13 changes: 13 additions & 0 deletions src/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,16 @@ div[class*="language-shell"] code::before {
html[data-theme='dark'] div[class*="language-shell"] code::before {
color: var(--ifm-color-gray-400);
}

/**************
** FOOTER
***************/
.footer__license-info {
margin-top: 0.5rem;
font-size: 0.85rem;
opacity: 0.8;
}

.footer__license-info a {
text-decoration: underline;
}
92 changes: 88 additions & 4 deletions src/openapi/check-vendored-yaml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ When making changes to this file, consider: https://virtru.atlassian.net/browse/
*/
import * as fs from 'fs';
import * as crypto from 'crypto';
import * as yaml from 'js-yaml';
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 fileHash(filePath: string): string {
if (!fs.existsSync(filePath)) return '';
const data = fs.readFileSync(filePath);
Expand Down Expand Up @@ -32,16 +36,70 @@ function downloadFile(url: string, dest: string): Promise<void> {
});
}

function fetchJson(url: string): Promise<any> {
return new Promise((resolve, reject) => {
import('https').then(https => {
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', () => {
try { resolve(JSON.parse(data)); }
catch (e) { reject(new Error(`Failed to parse JSON from ${url}: ${e}`)); }
});
}).on('error', reject);
}).catch(reject);
});
}

function fetchText(url: string): Promise<string> {
return new Promise((resolve, reject) => {
import('https').then(https => {
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', () => resolve(data));
}).on('error', reject);
}).catch(reject);
});
}

/**
* Recursively fetches all .yaml file paths under docs/openapi/ in the platform repo.
*/
async function fetchRemoteSpecPaths(dirPath = 'docs/openapi'): Promise<string[]> {
const specPaths: string[] = [];
const contents = await fetchJson(`${PLATFORM_API_BASE}/contents/${dirPath}`);

for (const item of contents) {
if (item.type === 'file' && item.name.endsWith('.yaml')) {
specPaths.push(item.path);
} else if (item.type === 'dir') {
specPaths.push(...await fetchRemoteSpecPaths(item.path));
}
}

return specPaths;
}

/**
* Returns true if the spec at the given raw URL has actual API paths defined
* (i.e. it is a real API spec, not a shared schema-only file like common or entity).
*/
async function hasApiPaths(rawUrl: string): Promise<boolean> {
const content = await fetchText(rawUrl);
const spec = yaml.load(content) as any;
return spec?.paths != null && Object.keys(spec.paths).length > 0;
}

async function main() {
let hasDiff = false;

// --- Check 1: vendored files are up to date ---
for (const spec of openApiSpecsArray) {
if (!spec.url) continue; // Only process specs with a URL
// absPaths is the absolute path to the spec file
if (!spec.url) continue;
const absPath = spec.specPath;
const tmpPath = absPath + '.tmp';
// Download to tmpPath
await downloadFile(spec.url, tmpPath);
// Compare hashes
const oldHash = fileHash(absPath);
const newHash = fileHash(tmpPath);
if (oldHash !== newHash) {
Expand All @@ -52,6 +110,32 @@ async function main() {
}
fs.unlinkSync(tmpPath);
}

// --- Check 2: no unregistered spec files in the platform repo ---
console.log('\n🔍 Checking for unregistered spec files in opentdf/platform...');
const registeredUrls = new Set(
openApiSpecsArray.flatMap(spec => spec.url ? [spec.url] : [])
);

const remoteSpecPaths = await fetchRemoteSpecPaths();

for (const remotePath of remoteSpecPaths) {
const expectedUrl = `${PLATFORM_RAW_BASE}/${remotePath}`;
if (registeredUrls.has(expectedUrl)) continue;

// Not registered — check if it actually has API paths (vs shared schema file)
if (await hasApiPaths(expectedUrl)) {
hasDiff = true;
console.error(
`❌ Unregistered spec found in platform repo: ${remotePath}\n` +
` Add an entry to openApiSpecsArray in src/openapi/preprocessing.ts with:\n` +
` url: '${expectedUrl}'`
);
} else {
console.log(`ℹ️ Skipping schema-only file (no paths): ${remotePath}`);
}
}

process.exit(hasDiff ? 1 : 0);
}

Expand Down
Loading