feat: Add MongoIdempotencyStoreOptions for MongoDB configuration
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

feat: Implement BsonJsonConverter for converting BsonDocument and BsonArray to JSON

fix: Update project file to include MongoDB.Bson package

test: Add GraphOverlayExporterTests to validate NDJSON export functionality

refactor: Refactor Program.cs in Attestation Tool for improved argument parsing and error handling

docs: Update README for stella-forensic-verify with usage instructions and exit codes

feat: Enhance HmacVerifier with clock skew and not-after checks

feat: Add MerkleRootVerifier and ChainOfCustodyVerifier for additional verification methods

fix: Update DenoRuntimeShim to correctly handle file paths

feat: Introduce ComposerAutoloadData and related parsing in ComposerLockReader

test: Add tests for Deno runtime execution and verification

test: Enhance PHP package tests to include autoload data verification

test: Add unit tests for HmacVerifier and verification logic
This commit is contained in:
StellaOps Bot
2025-11-22 16:42:56 +02:00
parent 967ae0ab16
commit dc7c75b496
85 changed files with 2272 additions and 917 deletions

View File

@@ -4,9 +4,9 @@ Keep this file in sync with `docs/implplan/SPRINT_0206_0001_0001_devportal.md`.
| Task ID | Status | Notes | Last Updated (UTC) |
| --- | --- | --- | --- |
| DEVPORT-62-001 | DOING | Select SSG, wire aggregate spec, nav/search scaffold. | 2025-11-22 |
| DEVPORT-62-002 | TODO | Schema viewer, examples, copy-curl, version selector. | 2025-11-22 |
| DEVPORT-63-001 | TODO | Try-It console against sandbox; token onboarding UX. | 2025-11-22 |
| DEVPORT-62-001 | DONE | Astro/Starlight scaffold + aggregate spec + nav/search. | 2025-11-22 |
| DEVPORT-62-002 | DONE | Schema viewer, examples, copy-curl, version selector. | 2025-11-22 |
| DEVPORT-63-001 | DONE | Try-It console against sandbox; token onboarding UX. | 2025-11-22 |
| DEVPORT-63-002 | TODO | Embed SDK snippets/quick starts from tested examples. | 2025-11-22 |
| DEVPORT-64-001 | TODO | Offline bundle target with specs + SDK archives; zero external assets. | 2025-11-22 |
| DEVPORT-64-002 | TODO | Accessibility tests, link checker, performance budgets. | 2025-11-22 |

View File

@@ -36,11 +36,12 @@ export default defineConfig({
{ slug: 'index' },
{ slug: 'guides/getting-started' },
{ slug: 'guides/navigation-search' },
{ slug: 'guides/examples' },
],
},
{
label: 'API',
items: [{ slug: 'api-reference' }],
items: [{ slug: 'api-reference' }, { slug: 'try-it-console' }],
},
{
label: 'Roadmap',

View File

@@ -7,7 +7,16 @@ import 'rapidoc/dist/rapidoc-min.js';
> The aggregate spec is composed from per-service OpenAPI files and namespaced by service (e.g., `/authority/...`). The bundled copy lives at `/api/stella.yaml` so offline builds stay self-contained.
<div class="version-select">
<label for="spec-version">Version</label>
<select id="spec-version" aria-label="API version selector">
<option value="/api/stella.yaml" selected>latest (aggregate)</option>
<option value="/api/stella.yaml">sandbox preview (same build)</option>
</select>
</div>
<rapi-doc
id="rapidoc"
spec-url="/api/stella.yaml"
render-style="read"
theme="dark"
@@ -25,13 +34,64 @@ import 'rapidoc/dist/rapidoc-min.js';
schema-style="tree"
default-schema-tab="schema"
sort-tags="true"
show-components="true"
sort-endpoints-by="path"
hide-schema-titles="false"
layout="row"
style="height: 80vh; border: 1px solid #1f2937; border-radius: 12px;"
style="height: 78vh; border: 1px solid #1f2937; border-radius: 12px;"
></rapi-doc>
## Quick copy-curl
<div class="copy-snippets">
<div class="snippet">
<header>Health check</header>
<pre><code id="curl-health">curl -X GET https://api.stellaops.local/authority/health \\
-H 'Accept: application/json' \\
-H 'User-Agent: stellaops-devportal/0.1.0'</code></pre>
<button data-copy="#curl-health">Copy</button>
</div>
<div class="snippet">
<header>Submit orchestration job</header>
<pre><code id="curl-orchestrator">curl -X POST https://api.stellaops.local/orchestrator/jobs \\
-H 'Authorization: Bearer $STELLAOPS_TOKEN' \\
-H 'Content-Type: application/json' \\
-d '{\"workflow\":\"sbom-verify\",\"source\":\"registry:example/app@sha256:...\"}'</code></pre>
<button data-copy="#curl-orchestrator">Copy</button>
</div>
</div>
## What to look for
- Per-operation `x-service` and `x-original-path` values expose provenance.
- Shared schemas live under `#/components/schemas` with namespaced keys.
- Shared schemas live under `#/components/schemas` with namespaced keys (use the **Schemas** panel).
- Servers list includes one entry per service; sandbox URLs will be added alongside prod.
<script type="module">
const selector = document.getElementById('spec-version');
const rapidoc = document.getElementById('rapidoc');
selector?.addEventListener('change', (evt) => {
const url = evt.target.value;
if (rapidoc) {
rapidoc.setAttribute('spec-url', url);
rapidoc.loadSpec(url);
}
});
document.querySelectorAll('button[data-copy]').forEach((btn) => {
btn.addEventListener('click', async () => {
const target = btn.getAttribute('data-copy');
const el = target ? document.querySelector(target) : null;
if (!el) return;
const text = el.textContent || '';
try {
await navigator.clipboard.writeText(text);
btn.textContent = 'Copied!';
setTimeout(() => (btn.textContent = 'Copy'), 1200);
} catch (err) {
btn.textContent = 'Copy failed';
setTimeout(() => (btn.textContent = 'Copy'), 1200);
console.error(err);
}
});
});
</script>

View File

@@ -0,0 +1,33 @@
---
title: Examples & Snippets
description: Ready-to-copy requests with deterministic headers and pinned versions.
---
## cURL quick starts
The snippets below are deterministic: pinned versions, explicit headers, and scope hints.
```bash
curl -X GET \\
https://api.stellaops.local/authority/health \\
-H 'Accept: application/json' \\
-H 'User-Agent: stellaops-devportal/0.1.0' \\
--retry 2 --retry-delay 1
```
```bash
curl -X POST \\
https://api.stellaops.local/orchestrator/jobs \\
-H 'Content-Type: application/json' \\
-H 'Authorization: Bearer $STELLAOPS_TOKEN' \\
-d '{\"workflow\":\"sbom-verify\",\"source\":\"registry:example/app@sha256:...\"}'
```
## How snippets are generated
- Targets align to the aggregate spec (`/api/stella.yaml`).
- Headers: `Accept`/`Content-Type` always explicit; User-Agent pinned to portal version.
- Retries kept low (`--retry 2`) to preserve determinism while tolerating transient sandboxes.
## Coming next
- Language SDK equivalents (DEVPORT-63-002).
- Operation-specific examples sourced directly from tested fixtures.

View File

@@ -7,7 +7,9 @@ description: Drop-by-drop updates for the DevPortal surface.
- ✅ Selected Astro + Starlight as the static site generator for deterministic offline builds.
- ✅ Added navigation scaffolding (Overview, Guides, API, Roadmap) with local search enabled.
- ✅ Embedded aggregate OpenAPI via RapiDoc using bundled `/api/stella.yaml`.
- 🔜 Schema explorer UI and copy-curl snippets (DEVPORT-62-002).
- ✅ Added schema viewer + version selector, copy-curl snippets, and example guide.
- ✅ Delivered Try-It console targeting sandbox with bearer-token onboarding and RapiDoc allow-try.
- 🔜 Operation-specific example rendering & SDK snippets (DEVPORT-63-002).
- 🔜 Try-It console against sandbox scopes (DEVPORT-63-001).
## How to contribute release entries

View File

@@ -0,0 +1,87 @@
---
title: Try-It Console
description: Run authenticated requests against the sandbox API with scoped tokens and offline-ready tooling.
---
import 'rapidoc/dist/rapidoc-min.js';
> Use this console to exercise the sandbox API. It runs fully client-side with no external assets. Supply a short-lived token with the scopes shown below. Nothing is sent to third-party services.
## Token onboarding
- Obtain a sandbox token from the Platform sandbox issuer (`/auth/oidc/token`) using the `client_credentials` flow.
- Required scopes (minimum): `stellaops.read`, `stellaops.write:sandbox`.
- Tokens should be short-lived (<15 minutes); refresh before each session.
- Paste only sandbox tokens here—**never** production credentials.
<div class="token-panel">
<label for="token-input">Bearer token</label>
<input id="token-input" type="password" autocomplete="off" placeholder="Paste sandbox token" />
<div class="token-actions">
<button id="token-apply">Apply to console</button>
<button id="token-clear" class="secondary">Clear</button>
</div>
<p class="hint">Token is stored in-memory only for this tab. Reload to remove.</p>
</div>
## Sandbox server
- Base URL: `https://sandbox.api.stellaops.local`
- Operations remain namespaced by service (e.g., `/authority/health`, `/orchestrator/jobs`).
<rapi-doc
id="sandbox-rapidoc"
spec-url="/api/stella.yaml"
render-style="focused"
theme="dark"
bg-color="#0b1220"
text-color="#e5e7eb"
primary-color="#0ea5e9"
nav-bg-color="#0f172a"
nav-text-color="#cbd5e1"
show-header="false"
allow-try="true"
allow-server-selection="true"
allow-spec-url-load="false"
allow-spec-file-load="false"
api-key-name="Authorization"
api-key-location="header"
regular-font="Space Grotesk"
mono-font="JetBrains Mono"
schema-style="tree"
default-schema-tab="schema"
sort-tags="true"
sort-endpoints-by="path"
hide-schema-titles="false"
layout="column"
style="height: 78vh; border: 1px solid #1f2937; border-radius: 12px;"
></rapi-doc>
## Tips
- Set the server dropdown to `https://sandbox.api.stellaops.local` before sending requests.
- Use small payloads; responses are truncated by RapiDoc if excessively large.
- Keep retries low to preserve determinism (default is none).
<script type="module">
const tokenInput = document.getElementById('token-input');
const applyBtn = document.getElementById('token-apply');
const clearBtn = document.getElementById('token-clear');
const doc = document.getElementById('sandbox-rapidoc');
const setToken = (value) => {
if (!doc) return;
const header = value ? `Bearer ${value.trim()}` : '';
doc.setAttribute('api-key-value', header);
doc.loadSpec(doc.getAttribute('spec-url'));
};
applyBtn?.addEventListener('click', () => {
const token = tokenInput?.value || '';
setToken(token);
applyBtn.textContent = 'Applied';
setTimeout(() => (applyBtn.textContent = 'Apply to console'), 1200);
});
clearBtn?.addEventListener('click', () => {
if (tokenInput) tokenInput.value = '';
setToken('');
});
</script>

View File

@@ -43,3 +43,118 @@ nav.sl-topnav {
background: rgba(255, 255, 255, 0.08);
border: 1px solid var(--sl-color-hairline);
}
.version-select {
display: inline-flex;
align-items: center;
gap: 0.5rem;
margin: 1rem 0;
padding: 0.75rem 1rem;
border: 1px solid var(--sl-color-hairline);
border-radius: 12px;
background: rgba(15, 23, 42, 0.6);
}
.version-select select {
background: #0f172a;
color: var(--sl-color-text);
border: 1px solid var(--sl-color-hairline);
padding: 0.4rem 0.6rem;
border-radius: 8px;
}
.copy-snippets {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
margin: 1rem 0 2rem 0;
}
.copy-snippets .snippet {
border: 1px solid var(--sl-color-hairline);
border-radius: 12px;
padding: 0.75rem;
background: rgba(15, 23, 42, 0.7);
}
.copy-snippets header {
font-weight: 600;
margin-bottom: 0.5rem;
}
.copy-snippets pre {
background: rgba(0, 0, 0, 0.35);
border-radius: 8px;
padding: 0.75rem;
overflow-x: auto;
border: 1px solid var(--sl-color-hairline);
}
.copy-snippets button {
margin-top: 0.6rem;
background: var(--sl-color-accent);
color: #0b1220;
border: none;
padding: 0.4rem 0.75rem;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
}
.copy-snippets button:hover {
filter: brightness(1.05);
}
.token-panel {
border: 1px solid var(--sl-color-hairline);
border-radius: 12px;
padding: 1rem;
background: rgba(15, 23, 42, 0.7);
margin: 1rem 0;
}
.token-panel label {
font-weight: 600;
display: block;
margin-bottom: 0.35rem;
}
.token-panel input {
width: 100%;
background: #0f172a;
color: var(--sl-color-text);
border: 1px solid var(--sl-color-hairline);
border-radius: 8px;
padding: 0.5rem 0.65rem;
}
.token-actions {
display: flex;
gap: 0.75rem;
margin-top: 0.75rem;
}
.token-actions button {
background: var(--sl-color-accent);
color: #0b1220;
border: none;
padding: 0.45rem 0.9rem;
border-radius: 8px;
font-weight: 700;
cursor: pointer;
}
.token-actions button.secondary {
background: transparent;
color: var(--sl-color-text);
border: 1px solid var(--sl-color-hairline);
}
.token-actions button:hover {
filter: brightness(1.05);
}
.hint {
margin-top: 0.4rem;
color: var(--sl-color-text-muted);
}