You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
22 KiB
282 lines
22 KiB
|
2 months ago
|
# tera-api
|
||
|
|
|
||
|
|
Initial mock backend for TERA Core-X48 PRO management APIs.
|
||
|
|
|
||
|
|
## First user task
|
||
|
|
|
||
|
|
Portable Go is installed under the repository `.tools/` directory. Run:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
cd services\tera-api
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File ..\..\scripts\use-go.ps1 test ./...
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File ..\..\scripts\use-go.ps1 run ./cmd/tera-api
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-linux-arm64-build.ps1
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-linux-arm64-build.ps1 -Command tera-logd
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-linux-arm64-build.ps1 -Command tera-hwd
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-linux-arm64-build.ps1 -Command tera-seriald
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-linux-arm64-build.ps1 -Command tera-serial-check
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-linux-arm64-build.ps1 -Command tera-serial-line-check
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-linux-arm64-serial-termios.ps1
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-target-rootfs-staging.ps1
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\check-target-rootfs-staging.ps1 -InitSystem buildroot
|
||
|
|
```
|
||
|
|
|
||
|
|
For a same-origin Direct Mode attachment load against a deployed target, keep
|
||
|
|
the web password in the process environment and run the dedicated client. The
|
||
|
|
client sends the browser-required `Origin` header and `tera.direct.v1`
|
||
|
|
subprotocol, consumes one-use stream tickets, keeps reading to service
|
||
|
|
WebSocket heartbeats, validates one welcome frame for every attachment, checks
|
||
|
|
the matching channel `session` logs, and closes every session during cleanup.
|
||
|
|
With `-attachments 48`, every CH01-CH48 channel is covered once without sending
|
||
|
|
serial payload; `192` covers four viewers per channel:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
$env:TERA_TARGET_PASSWORD = '<read from the protected lab credential source>'
|
||
|
|
powershell -NoProfile -ExecutionPolicy Bypass -File ..\..\scripts\use-go.ps1 run ./cmd/tera-target-session-load -base-url http://192.168.0.223:8083 -attachments 192 -hold-seconds 60
|
||
|
|
Remove-Item Env:\TERA_TARGET_PASSWORD
|
||
|
|
```
|
||
|
|
|
||
|
|
Then verify:
|
||
|
|
|
||
|
|
```powershell
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/system/status
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/system/services
|
||
|
|
Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"username":"admin","password":"mock-admin-secret"}' http://127.0.0.1:8080/api/v1/auth/login
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"Authorization"="Bearer <session-token>"} http://127.0.0.1:8080/api/v1/auth/logout
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/auth/me
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/auth/tokens
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"name":"automation"}' http://127.0.0.1:8080/api/v1/auth/tokens
|
||
|
|
Invoke-RestMethod -Method Delete -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/auth/tokens/token_000001
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/auth/users
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"username":"fieldops","password":"fieldops-secret-1","role":"port_operator"}' http://127.0.0.1:8080/api/v1/auth/users
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"enabled":false}' http://127.0.0.1:8080/api/v1/auth/users/fieldops
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"password":"fieldops-secret-2"}' http://127.0.0.1:8080/api/v1/auth/users/fieldops/password
|
||
|
|
Invoke-RestMethod -Method Delete -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/auth/users/fieldops
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/auth/groups
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/auth/permissions
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/config/status
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/config/export
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/time/settings
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"timezone":"Asia/Seoul","ntp_servers":["time1.example.local","time2.example.local"]}' http://127.0.0.1:8080/api/v1/time/settings
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/security/management-access
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"https_enabled":true,"https_port":8443,"ssh_enabled":true,"ssh_port":2222,"http_enabled":false,"http_port":80,"telnet_enabled":false,"telnet_port":23,"idle_timeout_minutes":30}' http://127.0.0.1:8080/api/v1/security/management-access
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"interfaces":[{"name":"Interface-1","address":"192.168.10.233/24","gateway":"192.168.10.1"}]}' http://127.0.0.1:8080/api/v1/network/running
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/ports
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/alarms/rules
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"mode":"Reverse Telnet"}' http://127.0.0.1:8080/api/v1/ports/CH01
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"enabled":false}' http://127.0.0.1:8080/api/v1/alarms/rules/auth_failures
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/config/apply
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"browser_time":"2026-06-16T10:31:12+09:00","timezone":"Asia/Seoul"}' http://127.0.0.1:8080/api/v1/time/sync-browser
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/time/sync-ntp
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"target":"192.168.0.1"}' http://127.0.0.1:8080/api/v1/diagnostics/network-test
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"target":"8.8.8.8","count":4}' http://127.0.0.1:8080/api/v1/diagnostics/network-test
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/diagnostics/support-bundle
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} 'http://127.0.0.1:8080/api/v1/logs/audit?actor=admin&order=desc&limit=100'
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} 'http://127.0.0.1:8080/api/v1/logs/system?severity=warning&keyword=failover&from=2026-06-15T00:00:00Z&to=2026-06-17T00:00:00Z'
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} 'http://127.0.0.1:8080/api/v1/logs/port?channel=CH01&keyword=LOGIN&actor=admin&from=2026-06-15T00:00:00Z&to=2026-06-17T00:00:00Z'
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} 'http://127.0.0.1:8080/api/v1/logs/links?kind=serial&resource=CH01'
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/logs/policy
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/logs/retention
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"port_days":180,"protected_usage_warning_pct":85}' http://127.0.0.1:8080/api/v1/logs/retention
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/logs/remote-syslog
|
||
|
|
Invoke-RestMethod -Method Patch -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"enabled":true,"host":"syslog.local","port":1514,"protocol":"tcp","facility":"local4"}' http://127.0.0.1:8080/api/v1/logs/remote-syslog
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"log_type":"port","channel":"CH01"}' http://127.0.0.1:8080/api/v1/logs/export
|
||
|
|
Invoke-WebRequest -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} -ContentType 'application/json' -Body '{"log_type":"port","channel":"CH01","actor":"admin","from":"2026-06-15T00:00:00Z","to":"2026-06-17T00:00:00Z"}' -OutFile tera-port-logs.jsonl http://127.0.0.1:8080/api/v1/logs/export/download
|
||
|
|
Invoke-RestMethod -Method Post -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/ports/CH01/restart
|
||
|
|
Invoke-RestMethod -Headers @{"X-Mock-Actor"="mock-admin"} http://127.0.0.1:8080/api/v1/operations
|
||
|
|
```
|
||
|
|
|
||
|
|
## Current scope
|
||
|
|
|
||
|
|
- Mock domain data with optional target-backed local service adapters and
|
||
|
|
bounded file-backed state for host and rootfs verification.
|
||
|
|
- In-memory `pending`/`running`/`persistent` config transaction state.
|
||
|
|
- JSON request bodies are bounded by `TERA_API_MAX_REQUEST_BYTES` and must
|
||
|
|
contain a single JSON value. Oversized bodies return `payload_too_large`
|
||
|
|
with HTTP 413; malformed or trailing JSON returns `validation_failed`.
|
||
|
|
- Audit events for user-verifiable command validation. By default these are
|
||
|
|
in-memory. Set `TERA_API_AUDIT_LOG` to a JSON Lines file path to enable
|
||
|
|
bounded file-backed prototype audit storage; set
|
||
|
|
`TERA_API_AUDIT_MAX_EVENTS` to control the retained event count.
|
||
|
|
- Config transaction state is in-memory by default. Set
|
||
|
|
`TERA_API_CONFIG_STORE` to a JSON file path to retain prototype
|
||
|
|
port, alarm, network, time, and log-retention `pending`/`running`/
|
||
|
|
`persistent` state across `tera-api` restarts. Prototype config export
|
||
|
|
returns running, persistent, and pending port/alarm/network/time/log-retention/
|
||
|
|
management-access/remote-syslog state and requires `config.read`.
|
||
|
|
- Operation state is in-memory by default. Set `TERA_API_OPERATION_STORE` to a
|
||
|
|
JSON file path to retain prototype operation results across `tera-api`
|
||
|
|
restarts. Operation result lookup and operation history listing require
|
||
|
|
`operation.read`.
|
||
|
|
- Prototype local auth users are in-memory by default. Set
|
||
|
|
`TERA_API_AUTH_STORE` to a JSON file path to retain prototype users with
|
||
|
|
nested password KDF records containing `algorithm`, `version`, `params`,
|
||
|
|
`salt`, and `hash`. Local password hashing uses Argon2id by default; the
|
||
|
|
record schema is versioned so a future FIPS-compatible
|
||
|
|
`pbkdf2-hmac-sha256` mode can be added without changing the auth store
|
||
|
|
shape. Local user creation and password reset enforce an eight-character
|
||
|
|
minimum by default. `TERA_API_MIN_PASSWORD_LENGTH` may raise that policy up
|
||
|
|
to 128 characters but cannot reduce it below eight. The target profile sets
|
||
|
|
`TERA_API_AUTH_STORE=/var/lib/tera-api/auth.json` so provisioned users and
|
||
|
|
disabled bootstrap accounts survive service restarts.
|
||
|
|
- Prototype bearer sessions use crypto-random tokens, store token hashes
|
||
|
|
in memory, expire after eight hours, and can be revoked through
|
||
|
|
`POST /api/v1/auth/logout`.
|
||
|
|
- Prototype API bearer tokens are available behind `auth.read`/`auth.write`.
|
||
|
|
Raw token material is returned only on creation, stored by hash, and bounded
|
||
|
|
by `TERA_API_AUTH_MAX_TOKENS` when configured. Token records are listed by
|
||
|
|
opaque `token_id` without exposing raw token material and can be revoked by
|
||
|
|
`DELETE /api/v1/auth/tokens/{token_id}`.
|
||
|
|
- Prototype local login tracks repeated failures in memory and temporarily
|
||
|
|
locks a normalized username after five failures for 15 minutes. Client
|
||
|
|
responses remain generic; lock details are recorded only in the audit log.
|
||
|
|
- Prototype local user, group, and permission read APIs are available behind
|
||
|
|
`auth.read`. Prototype local user creation, enable/disable updates, and
|
||
|
|
role updates, password resets/deletes are available behind `auth.write`.
|
||
|
|
These responses intentionally exclude password KDF records, salts, hashes,
|
||
|
|
session tokens, and token hashes. Deleting or demoting the last enabled
|
||
|
|
administrator is rejected to avoid local lockout. Disabling, deleting,
|
||
|
|
changing role, or resetting the password for a local user immediately revokes
|
||
|
|
that user's existing bearer sessions and API bearer tokens.
|
||
|
|
- Prototype audit log reads require `audit.read`; only `mock-admin` has this
|
||
|
|
permission in the current mock policy.
|
||
|
|
- System, structured port command/result, and serial/Ethernet link log search
|
||
|
|
require `log.read`; audited log export and NDJSON download require
|
||
|
|
`log.export`.
|
||
|
|
`GET /api/v1/logs/policy` exposes the 365-day maximum, command/result and link
|
||
|
|
capture, no-at-rest-encryption decision, and enabled bounded UART/Direct Mode
|
||
|
|
payload capture with a 4-KiB per-record maximum. The production environment connects `tera-api` to the
|
||
|
|
independent `tera-logd` Unix socket for authoritative reads/writes,
|
||
|
|
retention, health, and filtered NDJSON export.
|
||
|
|
- Mock log retention policy reads require `log.read`; updates require
|
||
|
|
`config.write`, participate in the config transaction, and preserve protected
|
||
|
|
logs across factory reset by policy. All retention values are limited to 1
|
||
|
|
through 365 days.
|
||
|
|
- In explicit host-prototype mode, `TERA_API_SYSTEM_LOG_STORE`,
|
||
|
|
`TERA_API_PORT_LOG_STORE`, and
|
||
|
|
`TERA_API_LINK_LOG_STORE` enable bounded JSON Lines prototype persistence;
|
||
|
|
`TERA_API_LOG_MAX_EVENTS` bounds each of those stores. Command and result
|
||
|
|
fields are credential-redacted and size-bounded before persistence. A
|
||
|
|
configured/enabled remote syslog target receives best-effort forwarded
|
||
|
|
records through the existing alarm-delivery boundary.
|
||
|
|
- Target packaging instead sets `TERA_API_LOG_SOCKET` to
|
||
|
|
`/run/tera-logd/log-store.sock` and enables the production scheduler with
|
||
|
|
`TERA_API_LOG_SCHEDULER_ENABLED=true`. It must not configure the prototype
|
||
|
|
JSON Lines paths at the same time.
|
||
|
|
- Mock remote syslog reads require `log.read`; updates require `config.write`,
|
||
|
|
participate in the config transaction, and intentionally contain no shared
|
||
|
|
secrets or credentials.
|
||
|
|
- Mock alarm rule read/update endpoints are available for Web UI flow
|
||
|
|
validation. Reads require `alarm.read`; updates are config transaction
|
||
|
|
changes and require `alarm.write`.
|
||
|
|
- Alarm delivery tests call the group-restricted `tera-alarmd` Unix socket in
|
||
|
|
target mode. `tera-alarmd` persists a bounded retry queue atomically,
|
||
|
|
restores queued/retry-pending work after restart, delivers local/web events,
|
||
|
|
and sends configured remote syslog over UDP or TCP without a shell. SMTP and
|
||
|
|
SNMP trap transports fail explicitly until protected credential storage is
|
||
|
|
implemented; no placeholder secret material is embedded in configuration.
|
||
|
|
- Mock serial channel inventory/detail reads require `port.read`. The current
|
||
|
|
mock policy grants it to `mock-admin` and `mock-port-operator`.
|
||
|
|
- Mock network state reads require `network.read`; only `mock-admin` has this
|
||
|
|
permission in the current mock policy. Mock network interface address/gateway
|
||
|
|
staging requires `network.write`, participates in the config transaction, and
|
||
|
|
becomes visible in running state after config apply.
|
||
|
|
- Mock dashboard system status reads require `system.read`; only `mock-admin`
|
||
|
|
has this permission in the current mock policy. Mock service health reads use
|
||
|
|
the same permission and report prototype logical service readiness.
|
||
|
|
- Mock config transaction status lookup requires `config.read`; only
|
||
|
|
`mock-admin` has this permission in the current mock policy. Mock config
|
||
|
|
export uses the same permission and intentionally excludes auth, session,
|
||
|
|
token, and password KDF material.
|
||
|
|
- Browser/PC time sync requires `time.sync`, calls the group-restricted
|
||
|
|
`tera-timed` Unix socket, returns an operation result, and records the final
|
||
|
|
audit outcome. `tera-timed` validates the bounded RFC3339 time and IANA
|
||
|
|
timezone, applies `/etc/localtime` transactionally, and restores the prior
|
||
|
|
timezone if the Linux clock update fails. The in-process mock is used only
|
||
|
|
when mock actors are explicitly enabled.
|
||
|
|
- Mock time settings read/update is available for maintenance flow validation.
|
||
|
|
Reads require `config.read`; updates require `config.write` and participate
|
||
|
|
in the config transaction.
|
||
|
|
- Mock management access policy read/update is available for security flow
|
||
|
|
validation. Reads require `config.read`; updates require `config.write`,
|
||
|
|
participate in the config transaction, and reject changes that disable every
|
||
|
|
HTTPS, SSH, and serial-console recovery path.
|
||
|
|
- Network-test and traceroute diagnostics require `diagnostics.run` and use a
|
||
|
|
bounded asynchronous operation queue in target mode. The process adapter
|
||
|
|
invokes only fixed absolute `ping`/`traceroute` executables without a shell,
|
||
|
|
revalidates targets, enforces request timeouts, bounds combined output, and
|
||
|
|
records accepted plus final audit events. Queue/worker counts are bounded and
|
||
|
|
unfinished work is marked failed on restart or shutdown. When
|
||
|
|
`TERA_API_SUPPORT_BUNDLE_DIR` is configured, support-bundle requests use the
|
||
|
|
same bounded queue to create mode-`0600` ZIP artifacts atomically. Bundles
|
||
|
|
include only system status, service health, redacted config export, bounded
|
||
|
|
audit/system/port events, and operation metadata; auth users, password KDF
|
||
|
|
records, bearer sessions, API token hashes, and secret material are excluded.
|
||
|
|
Artifact count, total bytes, and per-section bytes are bounded. Authorized
|
||
|
|
downloads use `GET /api/v1/diagnostics/support-bundles/{bundle_id}` with
|
||
|
|
`no-store`, checksum, and attachment headers and create a download audit.
|
||
|
|
- Green LED control is a real target hardware boundary, not mock serial data:
|
||
|
|
`hardware.read` lists the CH01–CH48 PCF8574 mapping and `hardware.write`
|
||
|
|
force/releases or pulses one green LED. `tera-api` stays unprivileged and
|
||
|
|
calls the group-restricted `tera-hwd` Unix socket; `tera-hwd` alone writes
|
||
|
|
the kernel `gpio-leds` brightness entries after the target DTB is active.
|
||
|
|
- Serial line configuration is routed through the separate `tera-seriald`
|
||
|
|
Unix-socket boundary. `tera-api` never opens `/dev/ttyWCH*`. The controller
|
||
|
|
accepts only the validated `fet3568j-c-20260721-v1` mapping: CH01-CH24 use
|
||
|
|
`/dev/ttyWCH4`-`/dev/ttyWCH27`, and CH25-CH48 use
|
||
|
|
`/dev/ttyWCH32`-`/dev/ttyWCH55`. Raw nodes 0-3 and 28-31 are excluded as the
|
||
|
|
unconnected direct CH384 UARTs. Missing or mismatched mapping evidence still
|
||
|
|
fails closed. See
|
||
|
|
`docs/sw-detail-design/serial-hardware-api-contract.md`.
|
||
|
|
- Port updates now stage the bounded full UART profile (supported baud rate,
|
||
|
|
5-8 data bits, none/even/odd parity, one or two stop bits, and none/RTS-CTS
|
||
|
|
flow control). Apply operations pass the complete profile to `tera-seriald`;
|
||
|
|
readback mismatch or partial failure restores all opened channels.
|
||
|
|
- Mock operation result lookup and operation history listing require
|
||
|
|
`operation.read`; only `mock-admin` has this permission in the current mock
|
||
|
|
policy.
|
||
|
|
- Prototype `X-Mock-Actor` auth/RBAC skeleton for mutating commands and
|
||
|
|
`GET /api/v1/auth/me` profile checks. Set
|
||
|
|
`TERA_API_ALLOW_MOCK_ACTORS=false` to disable this header-based prototype
|
||
|
|
bypass and require bearer session or API token authentication for protected
|
||
|
|
routes; CORS preflight responses also stop advertising `X-Mock-Actor` when
|
||
|
|
this bypass is disabled.
|
||
|
|
- Firmware upload is streamed through the protected `tera-updated` Unix socket;
|
||
|
|
`tera-api` does not own `/userdata/update` and cannot mutate partitions or the
|
||
|
|
eMMC layout. The current updater accepts validation-only packages and rejects
|
||
|
|
apply. Read-only diagnostics and explicitly configured remote syslog are the
|
||
|
|
only new external network actions.
|
||
|
|
The only implemented clock mutation crosses the narrow `tera-timed` local
|
||
|
|
socket; HTTP handlers and the unprivileged `tera-api` process cannot set the
|
||
|
|
system clock or write `/etc/localtime` directly.
|
||
|
|
- No production login, session token, password hash, external auth secret, or
|
||
|
|
TLS key storage exists in this prototype. File-backed audit/auth/config/
|
||
|
|
operation storage is prototype-only and is not a replacement for the
|
||
|
|
production `tera-logd`, product persistent configuration database, protected
|
||
|
|
secret storage, and operation journal paths. Prototype snapshot rewrites do
|
||
|
|
use same-directory temporary files, file and directory sync on Linux, mode
|
||
|
|
`0600`, atomic rename, and symbolic-link refusal so a crash cannot expose a
|
||
|
|
partially written JSON destination.
|
||
|
|
- API contract is documented in
|
||
|
|
`docs/sw-detail-design/web-api-contract.md`.
|
||
|
|
- Backend-to-target implementation and acceptance gates are documented in
|
||
|
|
`docs/sw-detail-design/backend-target-test-gates.md`.
|
||
|
|
- Green LED API and deployment details are documented in
|
||
|
|
`docs/sw-detail-design/green-led-api-contract.md` and
|
||
|
|
`target-bsp/docs/pcf8574-green-led-control.md`.
|
||
|
|
- Architecture/FigJam guardrails are documented in
|
||
|
|
`docs/sw-detail-design/architecture-figma-implementation-guardrails.md`.
|
||
|
|
|
||
|
|
## Next implementation steps
|
||
|
|
|
||
|
|
1. Replace prototype auth/RBAC storage with production session identity and
|
||
|
|
protected token storage. Direct Mode already reuses the common permission
|
||
|
|
and audit path and must not introduce a second auth store.
|
||
|
|
2. Add protected SMTP/SNMP credential storage before enabling those
|
||
|
|
`tera-alarmd` transports.
|
||
|
|
3. Replace the remaining prototype config and operation stores with product
|
||
|
|
persistence; authoritative log persistence is now owned by `tera-logd` but
|
||
|
|
still requires target Stage 4 application and soak evidence.
|
||
|
|
4. Keep update/recovery and GPT/eMMC changes disabled until their separate
|
||
|
|
device-side safety and rollback gates are explicitly approved.
|