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.
 
 
 
 
 
 
gudae d790e06737 Fix operation 2 listener validation and show selector aliases 2 months ago
..
cmd Improve port controls, session sharing and administrator log management 2 months ago
deploy Evaluate keyword alarms from serial RX journal records 2 months ago
internal Fix operation 2 listener validation and show selector aliases 2 months ago
scripts Initial source-only commit 2 months ago
vendor Initial source-only commit 2 months ago
README.md Initial source-only commit 2 months ago
go.mod Initial source-only commit 2 months ago
go.sum Initial source-only commit 2 months ago

README.md

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:

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:

$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:

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.