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
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ Open an issue before substantial implementation work so maintainers can confirm
4. Open a pull request using the repository template.
5. Address review feedback and ensure required status checks pass.

When adding a heading or installation option to `docs/installation.md`, update `docs/installation_builder.md` and `docs/_static/install-builder.mjs` in the same change. Keep the builder's options, generated Helm flags, prerequisites, and guide links aligned with the installation guide. For sections that do not map to a selectable option, include the relevant guidance or link in the builder page. Validate with `node --test tests/docs/*.test.mjs` and `uv run --project docs --locked sphinx-build -W --keep-going -b html -c docs . docs/_build/html`, then inspect the rendered builder.

## Developer Certificate Of Origin

External contributions require agreement to the [Developer Certificate of Origin 1.1](DCO.md). Every commit must include a `Signed-off-by` line. Add it automatically with the `-s` option:
Expand Down
7 changes: 5 additions & 2 deletions docs/_static/docs.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ pre, .admonition, .search-button { border-radius: 0; }
#install-command-builder .builder-settings { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .8rem; }
#install-command-builder .builder-settings > label { flex-direction: column; align-items: stretch; text-align: left; }
#install-command-builder input:not([type=checkbox]), #install-command-builder select { width: 100%; padding: .45rem; border: 1px solid var(--pst-color-border); border-radius: 0; background: var(--pst-color-background); color: var(--pst-color-text-base); }
.builder-modules { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; }
.builder-modules { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; align-items: start; }
.builder-module { background: var(--pst-color-surface); }
.builder-module:has(.builder-suboptions:not([hidden])) { grid-row: span 2; }
.builder-suboptions { padding-left: 1.5rem; }
.builder-modules label { padding: .5rem; background: var(--pst-color-surface); cursor: pointer; }
.builder-modules input { accent-color: var(--pst-color-primary); }
.builder-prerequisites { font-size: .9rem; }
#install-command-builder button { padding: .4rem .8rem; border: 1px solid var(--pst-color-border); border-radius: 0; background: var(--pst-color-surface); color: var(--pst-color-text-base); }
#install-command-builder [role=status] { margin-left: .6rem; }
#install-command-builder pre { margin-top: .6rem; padding: 1rem; white-space: pre; overflow: auto; }
@media (max-width: 600px) { #install-command-builder .builder-settings, .builder-modules { grid-template-columns: 1fr; } }
@media (max-width: 600px) { #install-command-builder .builder-settings, .builder-modules { grid-template-columns: 1fr; } .builder-module:has(.builder-suboptions:not([hidden])) { grid-row: auto; } }

#install-command-builder .builder-settings > label:has(input[type=checkbox]) { flex-direction: row; align-items: center; grid-column: 1 / -1; }
.builder-sizing { margin: 2rem 0; }
Expand Down
11 changes: 10 additions & 1 deletion docs/_static/install-builder.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export function buildCommand(state) {
set('llm.external.existingSecret', value('llmSecret'), true);
}
for (const name of ['ui', 'execution', 'observability', ...Object.keys(modules).filter(name => !observabilityServices.includes(name))]) set(`modules.${name}.enabled`, ['ui', 'execution'].includes(name) || enabled.has(name));
set('modules.bcm.redfish.enabled', enabled.has('bcm') && !!state.redfish);
for (const service of ['prometheus', 'alertmanager']) {
set(`observability.${service}Url`, enabled.has(service) ? value(`${service}Url`) : '', true);
}
Expand Down Expand Up @@ -111,10 +112,16 @@ if (root) {
const moduleGroup = document.createElement('fieldset'); moduleGroup.innerHTML = '<legend>Modules</legend><p>UI and execution are always enabled. Required dependencies are selected automatically.</p>';
const buttons = document.createElement('div'); buttons.className = 'builder-modules';
const inputs = new Map();
const redfishOptions = document.createElement('div'); redfishOptions.className = 'builder-suboptions';
const redfishLabel = document.createElement('label'); const redfishInput = document.createElement('input'); redfishInput.type = 'checkbox'; redfishInput.name = 'redfish';
redfishInput.addEventListener('change', () => {state.redfish = redfishInput.checked; update(false);}); redfishLabel.append(redfishInput, document.createTextNode('Read-only Redfish')); redfishOptions.append(redfishLabel);
for (const [name, label] of Object.entries(modules)) {
const wrapper = document.createElement('label'); const input = document.createElement('input'); input.type = 'checkbox'; input.name = name;
input.addEventListener('change', () => {const requested = new Set(state.modules); input.checked ? requested.add(name) : requested.delete(name); state.modules = [...requested]; update(true);});
wrapper.append(input, document.createTextNode(label)); buttons.append(wrapper); inputs.set(name, input);
wrapper.append(input, document.createTextNode(label)); inputs.set(name, input);
if (name === 'bcm') {
const block = document.createElement('div'); block.className = 'builder-module'; block.append(wrapper, redfishOptions); buttons.append(block);
} else buttons.append(wrapper);
}
moduleGroup.append(buttons); form.append(moduleGroup);
const settings = document.createElement('fieldset'); settings.innerHTML = '<legend>Connection settings</legend>';
Expand All @@ -134,6 +141,7 @@ if (root) {
}).then(data => {catalog = data; update(false);}).catch(error => {sizing.textContent = `Deployment footprint unavailable: ${error.message}`;});
function update(renderSettings) {
const enabled = enabledModules(state);
redfishOptions.hidden = !enabled.has('bcm'); redfishInput.checked = !!state.redfish;
for (const [name, input] of inputs) {input.checked = enabled.has(name); input.disabled = enabled.has(name) && !state.modules.includes(name);}
if (renderSettings) {
settingsBody.replaceChildren();
Expand Down Expand Up @@ -167,6 +175,7 @@ if (root) {
}
if (enabled.has('grafana')) notes.push(`Create ${state.grafanaSecret || fields.grafanaSecret[1]} with keys username and password.`);
if (enabled.has('bcm')) notes.push(`Create ${state.bcmSecret || fields.bcmSecret[1]} with key id_ecdsa; its SSH identity must bootstrap the read-only CMSH user.`);
if (enabled.has('bcm') && state.redfish) notes.push('Redfish reads node BMCs through the BCM head using credentials stored in BCM. Resets and configuration changes are unavailable. BMC TLS certificate verification is off by default; see the Redfish installation guide to configure it.');
if (enabled.has('research')) notes.push('Create iraop-secrets with NVIDIA_API_KEY, NVIDIA_CHAT_API_KEY and IRAOP_API_KEY; prepare the corpus directory.');
if (enabled.has('webSearch')) notes.push('Web search uses DuckDuckGo without an API key; the OpenClaw pod needs HTTPS egress to duckduckgo.com. Clear it for air-gapped installations.');
if (state.inference !== 'external') notes.push('Verify GPU, memory and model cache requirements in the on-prem inference section.');
Expand Down
2 changes: 2 additions & 0 deletions docs/bcm.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,5 @@ kubectl -n mosaic get secret mosaic-ui-auth \

Open `http://127.0.0.1:3210` on the workstation. Both forwarding processes
must remain running.

For optional BMC inventory and monitoring, follow the [Read-only Redfish installation](installation.md#read-only-redfish).
59 changes: 59 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,65 @@ helm upgrade mosaic "$MOSAIC_CHART" \

The SSH identity must be allowed to create or update the dedicated read-only CMSH user during startup.

### Read-only Redfish

Redfish lets the agent read a node's BMC when the node is down or unreachable in-band: power state,
hardware health, temperatures, fans, power supplies, BMC event logs, and firmware inventory. The
agent passes only a Base Command Manager hostname. The Base Command Manager adapter looks up the
BMC address and credentials through CMSH, the same lookup the Hardware Agent uses, and never returns
them to the model.

Prerequisites:

- The [Base Command Manager extension](#base-command-manager) is configured in `ssh-adapter` mode.
- The adapter's SSH identity can read `bmcsettings` and BMC interfaces through CMSH on the head node.
- The head node can reach the BMC network over HTTPS and has `curl`. Check one BMC from the head node:

```bash
curl -sk https://<bmc-address>/redfish/v1 | head -c 300; echo
```

Enable it:

```bash
helm upgrade mosaic "$MOSAIC_CHART" \
--devel \
-n mosaic \
--reuse-values \
--set modules.bcm.redfish.enabled=true \
--wait \
--timeout 12m
```

By default each request runs `curl` on the head node over the adapter's existing SSH session
(`modules.bcm.redfish.viaHeadNode=true`), because the head node is routed to the BMC network. The
BMC credential reaches `curl` on standard input, so it does not appear in process listings. Set
`viaHeadNode=false` only when the adapter pod itself can reach the BMCs. BMCs usually present
self-signed certificates, so `modules.bcm.redfish.verifyTls` defaults to `false`.
`modules.bcm.redfish.timeoutSeconds` (default `60`) bounds each request; some DGX BMCs take about
30 seconds to return the expanded firmware inventory.

The adapter enforces the following allowlist before it looks up any credential. Only `GET` is
used, and the only query parameters accepted are `$top`, `$skip`, and `$expand=.` limited to one
level, which is refused on the service root:

| Resource | Paths under `/redfish/v1` |
| --- | --- |
| Service root and collections | `/`, `Systems`, `Chassis`, `Managers` |
| Systems | `Systems/{id}` and its `Processors`, `Memory`, `Storage`, `EthernetInterfaces`, and `LogServices/{id}/Entries` |
| Chassis | `Chassis/{id}` and its `Thermal`, `ThermalSubsystem`, `Power`, `PowerSubsystem`, and `Sensors` |
| Managers | `Managers/{id}` and its `EthernetInterfaces` and `LogServices/{id}/Entries` |
| Firmware and tasks | `UpdateService/FirmwareInventory`, `TaskService/Tasks` |

Everything else is refused, including any path containing `Actions`, and `AccountService`,
`SessionService`, `CertificateService`, `EventService`, `SecureBoot`, `Bios/Settings`, and
`VirtualMedia`. Paths with `..`, `//`, `%`, or other query parameters are also refused. The adapter
also checks every resource embedded in a response, such as `$expand` results and continuation pages,
against the same allowlist. It reduces any embedded resource outside it to a bare link, so a BMC that
expands more than requested cannot return denied content. Fields named like passwords, tokens, or
secrets are redacted from responses. Resets and other BMC actions are not
available in any session mode.

### Research

To deploy the Research Agent and OpenSearch, set the embedding API key, active
Expand Down
2 changes: 2 additions & 0 deletions docs/installation_builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Select your inference path and modules to generate an installation command. Comp

CPU, RAM, GPUs and disk update automatically with your selections. Values come from this documentation version’s rendered Helm manifests. Different chart versions or site overrides can change the requirements.

Select Base Command Manager to expose the optional **Read-only Redfish** checkbox inside its module block. See the [Redfish installation guide](installation.md#read-only-redfish) for BMC credential resolution and TLS verification settings.

```{raw} html
<div id="install-command-builder"><noscript>Enable JavaScript to use the builder, or follow the <a href="installation.html">installation guide</a>.</noscript></div>
```
2 changes: 2 additions & 0 deletions docs/security_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ The read-only and administrative Base Command Manager paths use separate identit

Base Command Manager's configured profile remains authoritative. Enabling Base Command Manager administration requires an operator-provided credential with the intended cluster permissions.

When `modules.bcm.redfish.enabled=true`, the `bcm_redfish_*` tools read node BMCs in every mode, including View and automated sessions. They are never mutation tools. The model supplies only a Base Command Manager hostname and a path or named query. The Base Command Manager adapter resolves the BMC address and credentials through CMSH and does not return them. Its `RedfishPolicy` allowlist is enforced server-side before any credential lookup, and again on every resource embedded in a response, so `$expand` cannot reach a denied resource. It permits only `GET` on inventory, health, sensor, log, firmware, and task resources, and rejects any path containing `Actions`, as well as account, session, certificate, event, Secure Boot, BIOS settings, and virtual media resources. Responses have password, token, and secret fields redacted, and errors omit the BMC address. Like other read-only tools, Redfish is not a confidentiality boundary: anything the allowlist permits is visible to the session.

## Diagnostic Commands And SSH

Local `exec` runs inside the per-session OpenShell sandbox in View, Edit, Auto, and automated sessions. OpenShell enforces this boundary; the session guard does not parse or allowlist sandbox commands.
Expand Down
Binary file modified helm/mosaic-stack/files/agent-documentation.tar.gz
Binary file not shown.
Loading
Loading