Skip to content

feat(fleetnode): enroll nodes without miner signing keys#477

Draft
ankitgoswami wants to merge 1 commit into
codex/proto-creds-auth-review-fixesfrom
codex/proto-creds-phase-2
Draft

feat(fleetnode): enroll nodes without miner signing keys#477
ankitgoswami wants to merge 1 commit into
codex/proto-creds-auth-review-fixesfrom
codex/proto-creds-phase-2

Conversation

@ankitgoswami

@ankitgoswami ankitgoswami commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 2 makes new fleet-node enrollments credentials-only: the node registers with its identity key and no longer generates, sends, or persists a miner-signing keypair. The legacy proto field, database column, and state fields remain in place for the phase-3 cleanup, but new registrations store an empty byte slice for the retained miner_signing_pubkey column.

Stack: #471 -> #480 -> this PR. The diff here is relative to #480, which provides the server-side default-password remediation safety boundary. #482 is a sibling PR stacked on #480 for the Fleet UI remediation UX and is not required to review this fleet-node enrollment cleanup. Deleting the legacy field/column/state definitions is intentionally out of scope and belongs to phase 3.

Deployment note: ship the phase-1 proto plugin binary into fleet-node plugin directories before relying on this in environments where edge discovery must use the v2 credentials flow.

How it works

During enrollment, the fleet node generates only its identity keypair and sends RegisterRequest without miner_signing_pubkey. Gateway validation now allows that field to be omitted while still requiring the identity public key.

The enrollment service normalizes a missing miner-signing public key to empty bytes before inserting the fleet node, preserving the existing BYTEA NOT NULL schema without a migration. The saved fleet-node state keeps retained miner-signing fields empty, and plugin pairing startup tolerates the missing legacy key. Legacy asymmetric-auth pairing now returns an explicit error when no node signing key exists, while credentials-capable/basic-auth pairing continues to use supplied or discovered credentials.

Diagrams

flowchart LR
  A["fleetnode enroll"] --> B["generate identity keypair"]
  B --> C["RegisterRequest without miner_signing_pubkey"]
  C --> D["gateway validation accepts omitted field"]
  D --> E["enrollment service stores empty bytes"]
  E --> F["state.yaml keeps identity only"]
Loading
flowchart TD
  P["fleetnode pairing startup"] --> K{"miner-signing key present?"}
  K -->|"yes"| L["legacy asymmetric auth can run"]
  K -->|"no"| C{"driver supports credentials?"}
  C -->|"yes"| B["basic-auth pairing continues"]
  C -->|"no"| E["explicit legacy key error"]
Loading

Areas of the code involved

Area / package / file What changed Why it matters for review
proto/fleetnodegateway/v1 and generated outputs Removes the 32-byte validation requirement from RegisterRequest.miner_signing_pubkey while retaining the field Confirms the wire contract accepts credentials-only enrollment without phase-3 deletion
server/internal/fleetnode/bootstrap Stops generating/sending/writing miner-signing keys Main node enrollment behavior change
server/internal/domain/fleetnode/enrollment Normalizes omitted miner-signing pubkeys to empty bytes before persistence Keeps the current NOT NULL database shape without a migration
server/cmd/fleetnode Allows daemon pairing setup without the legacy signing key and errors only for legacy asymmetric-auth pairing Credentials-only nodes can boot while old asymmetric driver behavior remains explicit
Gateway/enrollment/bootstrap tests Adds validation and normalization coverage Pins the mixed-version compatibility boundary

Key technical decisions & trade-offs

Decision Trade-off
Keep the legacy proto field, state fields, and DB column until phase 3 Avoids mixed-version cleanup risk, but leaves temporary empty legacy data in new rows/state
Store empty bytes for omitted miner-signing public keys Avoids a migration in phase 2, but requires downstream code to treat empty as absent
Let fleet-node pairing initialize without the legacy signing key Credentials-only nodes can boot; truly legacy asymmetric-auth drivers now fail at pairing time with a clear error
Keep this branch independent from the Fleet UI PR Reviewers can handle fleet-node enrollment separately, but the stack has two sibling descendants from #480

Testing & validation

  • cd server && ../bin/go test ./internal/fleetnode/bootstrap
  • cd server && ../bin/go test ./cmd/fleetnode
  • cd server && ../bin/go test ./internal/domain/fleetnode/enrollment -run TestRegisterFleetNode_NormalizesMissingMinerSigningPubkeyToEmptyBytes
  • cd server && ../bin/go test ./internal/handlers/fleetnode/gateway -run TestRegisterRequestValidation
  • bin/buf lint
  • cd client && npm run format:check
  • git diff --check

@github-actions github-actions Bot added javascript Pull requests that update javascript code client server shared labels Jun 16, 2026
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Note: This is an automated security-focused code review generated by Codex.
It should be used as a supplementary check alongside human review.
False positives are possible - use your judgment.

Scope summary

  • Reviewed pull request diff only (490287757f4c98bc356f123e4c8f5be411e25272...df76b7a6851d673477e2fb440ba9d6b0cd377801, exact PR three-dot diff)
  • Model: gpt-5.5

💡 Click "edited" above to see previous reviews for this PR.


Review Summary

Overall Risk: LOW

Findings

[LOW] Optional Legacy Key Field Now Accepts Arbitrary Bytes

  • Category: Protobuf | gRPC | Reliability
  • Location: proto/fleetnodegateway/v1/fleetnodegateway.proto:38
  • Description: The PR removes the bytes.len = 32 validator from miner_signing_pubkey to allow credentials-only nodes to omit it, but it also allows non-empty malformed or oversized values. The handler passes this field directly into enrollment persistence, and the service only normalizes nil to an empty byte slice.
  • Impact: A custom or stale client with a valid enrollment code can register a fleet node with an invalid legacy public key, breaking the invariant that non-empty values are Ed25519 public keys. This can also persist unnecessarily large data into fleet_node.miner_signing_pubkey up to the transport/database limit.
  • Recommendation: Keep the field optional, but reject non-empty values whose length is not 32 bytes. This can be done with a CEL/protovalidate rule or an explicit service-level guard before CreateFleetNode, plus a regression test for non-empty invalid lengths.

Notes

No auth bypass, SQL injection, command injection, pool-hijack, plugin trust-boundary, frontend, infrastructure, or Rust ASIC plugin issues were evident in the reviewed diff.

I attempted the touched Go test packages, but the environment is read-only and go test failed before execution because it could not create /home/runner/go for the module cache.


Generated by Codex Security Review |
Triggered by: @ankitgoswami |
Review workflow run

@ankitgoswami ankitgoswami force-pushed the feat/proto-creds-auth branch from a0633c2 to 4f8863d Compare June 16, 2026 21:53
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from 223c620 to 9142fcf Compare June 16, 2026 21:53
@ankitgoswami ankitgoswami changed the base branch from feat/proto-creds-auth to codex/proto-creds-auth-review-fixes June 16, 2026 21:54
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 0897894 to 10ef01c Compare June 16, 2026 22:13
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from 9142fcf to e0f8d8a Compare June 16, 2026 22:13
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 46d3000 to 60df615 Compare June 16, 2026 22:42
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch 2 times, most recently from 040835c to 07bd80d Compare June 16, 2026 22:55
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 1239c48 to 298076a Compare June 16, 2026 23:00
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from 07bd80d to ede8e5f Compare June 16, 2026 23:00
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from a8d834e to 4cb6a53 Compare June 16, 2026 23:31
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch 2 times, most recently from 4a54f48 to b301110 Compare June 16, 2026 23:40
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 4cb6a53 to 1193bc2 Compare June 16, 2026 23:40
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 1193bc2 to 23e0fcc Compare June 16, 2026 23:52
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from b301110 to e8b95c4 Compare June 16, 2026 23:53
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 23e0fcc to 4e5a507 Compare June 16, 2026 23:59
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from e8b95c4 to d4a2e54 Compare June 17, 2026 00:00
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 4e5a507 to f524067 Compare June 17, 2026 00:10
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from d4a2e54 to 890ed98 Compare June 17, 2026 00:10
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from f524067 to 65dd2a6 Compare June 17, 2026 00:12
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from 890ed98 to 03b64ba Compare June 17, 2026 00:12
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 65dd2a6 to 00dafce Compare June 17, 2026 00:15
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from 03b64ba to 0094f07 Compare June 17, 2026 00:15
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 00dafce to 780b195 Compare June 17, 2026 00:27
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from 0094f07 to bdad85e Compare June 17, 2026 00:27
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 780b195 to 92a985a Compare June 17, 2026 15:47
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from bdad85e to 6e4f9aa Compare June 17, 2026 15:47
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 92a985a to 363b79d Compare June 17, 2026 16:54
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from 6e4f9aa to ce4e79c Compare June 17, 2026 16:54
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch from 363b79d to 49b1daa Compare June 17, 2026 17:34
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from ce4e79c to 73308a9 Compare June 17, 2026 17:35
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-auth-review-fixes branch 2 times, most recently from d40c0f6 to 4902877 Compare June 17, 2026 19:15
@ankitgoswami ankitgoswami force-pushed the codex/proto-creds-phase-2 branch from 73308a9 to df76b7a Compare June 17, 2026 19:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client javascript Pull requests that update javascript code server shared

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant