Skip to content
This repository was archived by the owner on Jan 5, 2026. It is now read-only.

Conversation

@troian
Copy link
Member

@troian troian commented Oct 13, 2025

https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-036-arbitrary-signature.md

🌟 PR Title

[Use a clear, concise title that reflects the change]

📝 Description

[Explain what this PR does in 2-3 sentences. Include context about the feature or problem being solved]

🔧 Purpose of the Change

  • New feature implementation
  • Bug fix
  • Documentation update
  • Code refactoring
  • Dependency upgrade
  • Other: [specify]

📌 Related Issues

  • Closes #ISSUE_NUMBER
  • References #ISSUE_NUMBER

✅ Checklist

  • I've updated relevant documentation
  • Code follows Akash Network's style guide
  • I've added/updated relevant unit tests
  • Dependencies have been properly updated
  • I agree and adhered to the Contribution Guidelines

📎 Notes for Reviewers

[Include any additional context, architectural decisions, or specific areas to focus on]

Summary by CodeRabbit

  • New Features

    • Added ES256KADR36 JWT signing/verification and an off-chain data signing message for arbitrary payloads.
    • Exposed signer and verifier abstractions for easier JWT integration.
  • Documentation

    • Provider docs updated with workloads schema (Workload, WorkloadReplica, WorkloadService, WorkloadStatus) and TOC entries.
  • Tests

    • Expanded JWT tests to cover multiple algorithms with new valid/invalid cases and subtests.

@coderabbitai
Copy link

coderabbitai bot commented Oct 13, 2025

Walkthrough

Adds an off-chain signing proto/message (MsgSignData) and its Cosmos SDK msg, introduces a new JWT signing method ES256KADR36 that uses ADR-36 style sign bytes, adds signer/verifier abstractions, refactors ES256K path to use them, updates JWT tests/fixtures, and extends provider docs with workloads entries.

Changes

Cohort / File(s) Summary
Provider docs
docs/proto/provider.md
Adds documentation and TOC entries for akash/inventory/v1/workloads.proto messages: Workload, WorkloadReplica, WorkloadService, WorkloadStatus.
Offchain sign proto & SDK msg
proto/node/akash/base/offchain/sign/sign.proto, go/node/types/offchain/sign/sign.go
Adds MsgSignData proto (signer, data) and implements corresponding MsgSignData SDK message with routing, validation, signers, GetSignBytes and StdSignBytes helper.
JWT signer/verifier abstractions
go/util/jwt/signer.go, go/util/jwt/verifier.go
Adds SignerI/Signer and VerifyI/Verify types with constructors and accessors (GetAddress, Pubkey).
ES256K JWT refactor
go/util/jwt/es256k.go
Removes previously exported signer types from this file and updates verification to use VerifyI; core ES256K sign/verify logic retained.
New JWT method ES256KADR36
go/util/jwt/es256kadr36.go
Adds SigningMethodES256KADR36 that builds ADR-36 StdSignBytes with MsgSignData, signs via SignerI, verifies via VerifyI, registers the method (Alg "ES256KADR36").
Tests and fixtures
go/util/jwt/es256k_test.go, go/util/jwt/jwt_test.go, go/util/jwt/suite_test.go, testdata/jwt/cases_es256k.json, testdata/jwt/cases_jwt.json.tmpl
Converts tests to subtests, introduces NewSigner/NewVerifier usage, parameterizes tests across ES256K and ES256KADR36, updates fixtures and adds alg fields; exposes addr/pubKey in test suite.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App
  participant JWT as ES256KADR36
  participant Signer as SignerI (keyring)
  participant Offchain as StdSignBytes(MsgSignData)

  App->>JWT: Sign(signingString, signer)
  note right of JWT #DDEBF7: Wrap signingString in MsgSignData (signer,data)
  JWT->>Offchain: Build StdSignBytes(chainID,..., msgs=[MsgSignData])
  Offchain-->>JWT: signBytes
  JWT->>Signer: SignByAddress(addr, signBytes)
  Signer-->>JWT: signature
  JWT-->>App: signature segment
Loading
sequenceDiagram
  autonumber
  participant App
  participant Parser as jwt.Parse(WithValidMethods)
  participant Method as ES256K / ES256KADR36
  participant Ver as VerifyI

  App->>Parser: Parse(token, keyfunc)
  Parser->>Method: Verify(signingString, signature, key)
  alt ES256KADR36
    note right of Method #F7F3DE: Recreate MsgSignData -> StdSignBytes
  else ES256K
    note right of Method #F7F3DE: Verify raw signingString
  end
  Method->>Ver: Pubkey().VerifySignature(message, signature)
  Method-->>Parser: ok / jwt.ErrTokenSignatureInvalid
  Parser-->>App: claims or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I twitch my nose at new protobuf light,
ADR-36 signs the JWT tonight.
Two methods hop, one verify true,
Tests updated, docs in view.
A rabbit nods: small changes, big delight. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description remains as the unfilled template with placeholders and does not include a summary of the changes, the purpose checkboxes, related issue references, a completed checklist, or any notes for reviewers. Please update the description by providing a 2–3 sentence overview of what the PR does, marking the appropriate purpose checkbox, listing any related issues, completing the checklist items, and adding any context or notes for reviewers.
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title accurately highlights the main change by referencing the go/util/jwt package and the ADR36 specification for JWT signing, which corresponds to the core feature introduced in this pull request.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jwt-adr-36

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8bdcb7 and 3e24bcb.

⛔ Files ignored due to path filters (2)
  • go/inventory/v1/workloads.pb.go is excluded by !**/*.pb.go
  • go/node/types/offchain/sign/sign.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (12)
  • docs/proto/provider.md (2 hunks)
  • go/node/types/offchain/sign/sign.go (1 hunks)
  • go/util/jwt/es256k.go (1 hunks)
  • go/util/jwt/es256k_test.go (2 hunks)
  • go/util/jwt/es256kadr36.go (1 hunks)
  • go/util/jwt/jwt_test.go (6 hunks)
  • go/util/jwt/signer.go (1 hunks)
  • go/util/jwt/suite_test.go (3 hunks)
  • go/util/jwt/verifier.go (1 hunks)
  • proto/node/akash/base/offchain/sign/sign.proto (1 hunks)
  • testdata/jwt/cases_es256k.json (3 hunks)
  • testdata/jwt/cases_jwt.json.tmpl (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • testdata/jwt/cases_jwt.json.tmpl
  • go/util/jwt/verifier.go
🧰 Additional context used
🧬 Code graph analysis (6)
go/util/jwt/signer.go (1)
go/testutil/ids.go (1)
  • Keyring (18-22)
go/util/jwt/es256k_test.go (3)
go/util/jwt/signer.go (1)
  • NewSigner (26-31)
go/util/jwt/verifier.go (2)
  • NewVerifier (21-26)
  • Verify (14-17)
go/util/jwt/jwt.go (1)
  • Claims (90-96)
go/node/types/offchain/sign/sign.go (1)
go/node/types/offchain/sign/sign.pb.go (3)
  • MsgSignData (27-32)
  • MsgSignData (36-36)
  • MsgSignData (37-39)
go/util/jwt/es256k.go (1)
go/util/jwt/verifier.go (1)
  • VerifyI (9-12)
go/util/jwt/jwt_test.go (3)
go/util/jwt/jwt.go (1)
  • Claims (90-96)
go/util/jwt/signer.go (2)
  • Signer (15-18)
  • NewSigner (26-31)
go/util/jwt/verifier.go (1)
  • NewVerifier (21-26)
go/util/jwt/es256kadr36.go (4)
go/util/jwt/signer.go (2)
  • SignerI (9-12)
  • Signer (15-18)
go/node/types/offchain/sign/sign.go (1)
  • StdSignBytes (61-82)
go/node/types/offchain/sign/sign.pb.go (3)
  • MsgSignData (27-32)
  • MsgSignData (36-36)
  • MsgSignData (37-39)
go/util/jwt/verifier.go (2)
  • Verify (14-17)
  • VerifyI (9-12)
🪛 Buf (1.58.0)
proto/node/akash/base/offchain/sign/sign.proto

4-4: import "gogoproto/gogo.proto": file does not exist

(COMPILE)

🪛 Gitleaks (8.28.0)
testdata/jwt/cases_es256k.json

[high] 4-4: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


[high] 15-15: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


[high] 29-29: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


[high] 53-53: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


[high] 64-64: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

🪛 LanguageTool
docs/proto/provider.md

[grammar] ~84-~84: There might be a mistake here.
Context: ... - akash/inventory/v1/workloads.proto - Workload ...

(QB_NEW_EN)


[grammar] ~85-~85: There might be a mistake here.
Context: ...ory/v1/workloads.proto) - Workload - [WorkloadReplica](#akash.inventory.v1.Wor...

(QB_NEW_EN)


[grammar] ~86-~86: There might be a mistake here.
Context: ...ory.v1.Workload) - WorkloadReplica - [WorkloadService](#akash.inventory.v1.Wor...

(QB_NEW_EN)


[grammar] ~87-~87: There might be a mistake here.
Context: ...WorkloadReplica) - WorkloadService - [WorkloadStatus](#akash.inventory.v1.Work...

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.18.1)
docs/proto/provider.md

84-84: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


85-85: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


86-86: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


87-87: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


88-88: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


1067-1067: Headings must start at the beginning of the line

(MD023, heading-start-left)


1073-1073: Headings must start at the beginning of the line

(MD023, heading-start-left)


1080-1080: Link fragments should be valid

(MD051, link-fragments)


1090-1090: Headings must start at the beginning of the line

(MD023, heading-start-left)


1106-1106: Headings must start at the beginning of the line

(MD023, heading-start-left)


1121-1121: Headings must start at the beginning of the line

(MD023, heading-start-left)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: go
  • GitHub Check: test
  • GitHub Check: coverage
  • GitHub Check: go
🔇 Additional comments (26)
go/util/jwt/signer.go (1)

8-31: LGTM! Clean abstraction for JWT signing.

The signer abstraction properly composes keyring.Signer with address retrieval. The constructor returns the interface type, which is good practice for dependency injection. The compile-time assertion ensures type safety.

go/util/jwt/suite_test.go (2)

24-25: LGTM! Proper test suite setup for multi-algorithm support.

Adding addr and pubKey fields aligns with the new signer/verifier abstractions and enables per-algorithm test flows.


50-52: LGTM! Fields properly initialized.

The address and public key are correctly extracted from the keyring info.

testdata/jwt/cases_es256k.json (2)

4-4: Test fixture tokens flagged by static analysis (expected).

The JWT tokens in this test data file are intentionally included as test fixtures and are not security concerns. The Gitleaks warnings can be safely ignored.


27-75: LGTM! Comprehensive ES256KADR36 test coverage.

The new test cases cover multiple scenarios:

  • Valid signature with full claims (including temporal claims and scoped leases)
  • Valid signature with minimal claims
  • Invalid signature case

The test structure is consistent with existing ES256K cases.

docs/proto/provider.md (2)

84-89: Documentation formatting issues in auto-generated file.

The static analysis tools flagged several formatting issues (unordered list indentation, heading placement). Since this is an auto-generated file (line 1 states "This file is auto-generated. Please do not modify it yourself."), these issues should be addressed in the documentation generator rather than manually edited here.

Consider fixing the documentation generator to ensure:

  • Proper list indentation (MD007)
  • Headings start at the beginning of lines (MD023)
  • Valid link fragments (MD051)

1063-1135: LGTM! Workloads proto documentation properly generated.

The documentation for the new workloads.proto messages (Workload, WorkloadReplica, WorkloadService, WorkloadStatus) is complete and properly structured.

go/util/jwt/es256k.go (1)

33-44: LGTM! Verification refactored to use new abstraction.

The change from cryptotypes.PubKey to VerifyI aligns with the new verifier abstraction. The verification logic remains correct, accessing the public key via key.Pubkey().

proto/node/akash/base/offchain/sign/sign.proto (1)

8-20: LGTM! MsgSignData properly defined for ADR-36 signing.

The message structure is correct for off-chain arbitrary signing:

  • signer field holds the account address
  • data field holds the raw bytes to be signed
  • Gogoproto annotations ensure proper JSON serialization
go/util/jwt/es256k_test.go (1)

42-80: LGTM! Excellent test refactor with improved structure.

The changes improve test quality:

  • Subtests via t.Run provide better isolation and clearer failure messages
  • Constructor-based signer/verifier objects align with new abstractions
  • Per-test assertions scoped to each subtest
  • Proper handling of both success and failure cases via MustFail flag

The test structure now supports multiple signing algorithms cleanly.

go/util/jwt/es256kadr36.go (4)

76-87: LGTM! Amino registration properly configured.

The init() function correctly:

  • Creates a Legacy Amino codec
  • Registers MsgSignData with the name "sign/MsgSignData" (line 78)
  • Initializes SigningMethodES256KADR36
  • Registers the signing method with JWT

This addresses the ADR-36 amino type registration requirement.

Based on previous review comments, the amino registration concern has been properly resolved.


32-50: LGTM! Sign method correctly implements ADR-36 signing.

The implementation:

  • Wraps the signing string in MsgSignData with raw bytes (no double encoding)
  • Uses StdSignBytes to create ADR-36 compliant sign bytes
  • Uses empty chainID and zero values for account number/sequence, which is correct for ADR-36 off-chain signing
  • Signs via SignByAddress from the keyring

Based on previous review comments, the double base64 encoding concern has been properly resolved—line 38 uses []byte(signingString) directly.


52-70: LGTM! Verify method correctly reconstructs ADR-36 sign bytes.

The verification:

  • Reconstructs identical StdSignBytes using the same empty/zero values
  • Uses raw signing string bytes (no double encoding)
  • Verifies via Pubkey().VerifySignature
  • Returns appropriate JWT error on signature mismatch

Based on previous review comments, the implementation correctly uses raw bytes without double base64 encoding.


35-40: ADR-36 compliance confirmed
Empty chainID (""), account_number 0, sequence 0, timeout 0 match the ADR-036 spec.

go/util/jwt/jwt_test.go (6)

6-6: LGTM!

The new imports (fmt and sdk) are necessary for the multi-algorithm test expansion.

Also applies to: 16-16


30-30: LGTM!

The Alg field addition enables the test suite to track and validate algorithm-specific behavior.


48-88: LGTM!

The refactor to support multiple signing algorithms is well-structured:

  • Efficiently generates test cases for both ES256K and ES256KADR36
  • Correctly constructs JWT components (header, claims, signature) per algorithm
  • Properly initializes the Signer with keyring and address
  • Sets Expected.Alg for downstream verification

95-98: LGTM!

The per-algorithm signer/verifier initialization correctly supports the multi-algorithm test flow.


100-100: LGTM!

The signing and verification flow correctly leverages the new signer/verifier abstractions and validates both ES256K and ES256KADR36 algorithms.

Also applies to: 113-114, 122-123


191-199: LGTM!

The test case aggregation correctly handles the multi-algorithm expansion, collecting all generated test cases into a single slice for execution.

go/node/types/offchain/sign/sign.go (6)

18-21: LGTM!

The compile-time interface assertions ensure MsgSignData correctly implements sdk.Msg and legacytx.LegacyMsg.


28-30: LGTM!

The Type() method correctly implements the sdk.Msg interface.


33-39: LGTM!

The ValidateBasic() method correctly validates the signer address with appropriate error wrapping.


42-49: LGTM!

The GetSigners() method follows the standard Cosmos SDK pattern, where panics are acceptable since ValidateBasic() should catch invalid addresses before this is called.


56-58: LGTM!

The Route() method correctly implements the legacytx.LegacyMsg interface.


60-82: LGTM with dependency on Amino registration.

The StdSignBytes() function correctly constructs ADR-036 compliant sign bytes following the standard Cosmos SDK pattern. The panic on marshal errors is consistent with the Must* pattern used throughout the SDK.

Note: This function's correctness depends on proper legacy Amino codec registration (see comment on lines 52-54).

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (7)
proto/node/akash/base/offchain/sign/sign.proto (1)

16-19: Consider adding size validation for the data field.

The data field accepts arbitrary bytes without size constraints in the protobuf definition. Consider adding validation logic in the Go implementation to prevent excessively large payloads that could cause memory or performance issues.

Would you like me to suggest a validation approach in the Go implementation (sign.go)?

go/node/types/offchain/sign/sign.go (2)

25-32: Add validation for data size limits.

As noted in the protobuf review, consider adding a maximum size check for the Data field in ValidateBasic to prevent excessively large payloads:

 func (m MsgSignData) ValidateBasic() error {
 	if _, err := sdk.AccAddressFromBech32(m.Signer); err != nil {
 		return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "MsgSignData: Invalid Signer Address")
 	}
+
+	// Prevent excessively large payloads (e.g., 1MB limit)
+	const maxDataSize = 1 * 1024 * 1024
+	if len(m.Data) > maxDataSize {
+		return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "MsgSignData: Data exceeds maximum size")
+	}
 
 	return nil
 }

34-42: Document panic invariant in GetSigners
Add a comment above GetSigners stating that it intentionally panics on invalid Bech32 and relies on ValidateBasic having been called first, mirroring other Cosmos SDK message implementations.

go/util/jwt/es256kadr36_test.go (1)

55-60: Fix trivial assertion; compare decoded bytes, not bytes vs string

Comparing sig ([]byte) with parts[2] (string) is vacuous. Compare sig with dsig.

- require.NotEqual(s.T(), sig, parts[2])
+ require.Equal(s.T(), sig, dsig, "raw signature bytes must match decoded JWT segment")
go/util/jwt/es256kadr36.go (2)

45-46: Clarify error for invalid key type

It expects a SignerI, not specifically a Ledger privkey. Update the message.

- return nil, fmt.Errorf("%w: ES256KADR36 sign expects cryptotypes.LedgerPrivKey", jwt.ErrInvalidKeyType)
+ return nil, fmt.Errorf("%w: ES256KADR36 Sign expects a jwt.SignerI (keyring.Signer with address)", jwt.ErrInvalidKeyType)

65-66: Unify verify invalid key error

Mirror Sign’s phrasing for consistency and clarity.

- return fmt.Errorf("%w: ES256KADR36 verify expects cryptotypes.PubKey", jwt.ErrInvalidKeyType)
+ return fmt.Errorf("%w: ES256KADR36 Verify expects a jwt.VerifyI (PubKey with address)", jwt.ErrInvalidKeyType)
go/util/jwt/signer.go (1)

26-31: Consider narrowing constructor param to the minimal interface

Accept keyring.Signer instead of keyring.Keyring to reduce coupling.

-func NewSigner(kr keyring.Keyring, addr sdk.Address) SignerI {
+func NewSigner(kr keyring.Signer, addr sdk.Address) SignerI {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab60646 and 4f7f673.

⛔ Files ignored due to path filters (2)
  • go/inventory/v1/workloads.pb.go is excluded by !**/*.pb.go
  • go/node/types/offchain/sign/sign.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (12)
  • docs/proto/provider.md (2 hunks)
  • go/node/types/offchain/sign/sign.go (1 hunks)
  • go/util/jwt/es256k.go (0 hunks)
  • go/util/jwt/es256k_test.go (1 hunks)
  • go/util/jwt/es256kadr36.go (1 hunks)
  • go/util/jwt/es256kadr36_test.go (1 hunks)
  • go/util/jwt/signer.go (1 hunks)
  • go/util/jwt/suite_test.go (4 hunks)
  • go/util/jwt/verifier.go (1 hunks)
  • proto/node/akash/base/offchain/sign/sign.proto (1 hunks)
  • testdata/jwt/cases_es256kadr36.json (1 hunks)
  • testdata/jwt/jwt.go (1 hunks)
💤 Files with no reviewable changes (1)
  • go/util/jwt/es256k.go
🧰 Additional context used
🧬 Code graph analysis (5)
go/util/jwt/signer.go (1)
go/testutil/ids.go (1)
  • Keyring (18-22)
go/node/types/offchain/sign/sign.go (1)
go/node/types/offchain/sign/sign.pb.go (3)
  • MsgSignData (27-32)
  • MsgSignData (36-36)
  • MsgSignData (37-39)
go/util/jwt/es256kadr36.go (3)
go/util/jwt/signer.go (2)
  • SignerI (9-12)
  • Signer (15-18)
go/node/types/offchain/sign/sign.pb.go (3)
  • MsgSignData (27-32)
  • MsgSignData (36-36)
  • MsgSignData (37-39)
go/util/jwt/verifier.go (2)
  • Verify (14-17)
  • VerifyI (9-12)
go/util/jwt/es256kadr36_test.go (5)
go/util/jwt/suite_test.go (1)
  • IntegrationTestSuite (19-26)
testdata/jwt/jwt.go (1)
  • GetTestsFile (12-30)
go/util/jwt/signer.go (1)
  • Signer (15-18)
go/util/jwt/es256kadr36.go (1)
  • SigningMethodES256KADR36 (26-26)
go/util/jwt/verifier.go (2)
  • Verify (14-17)
  • NewVerifier (21-26)
go/util/jwt/es256k_test.go (1)
go/util/jwt/verifier.go (2)
  • Verify (14-17)
  • NewVerifier (21-26)
🪛 Buf (1.58.0)
proto/node/akash/base/offchain/sign/sign.proto

4-4: import "gogoproto/gogo.proto": file does not exist

(COMPILE)

🪛 Gitleaks (8.28.0)
testdata/jwt/cases_es256kadr36.json

[high] 4-4: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 markdownlint-cli2 (0.18.1)
docs/proto/provider.md

84-84: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


85-85: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


86-86: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


87-87: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


88-88: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


1067-1067: Headings must start at the beginning of the line

(MD023, heading-start-left)


1073-1073: Headings must start at the beginning of the line

(MD023, heading-start-left)


1080-1080: Link fragments should be valid

(MD051, link-fragments)


1090-1090: Headings must start at the beginning of the line

(MD023, heading-start-left)


1106-1106: Headings must start at the beginning of the line

(MD023, heading-start-left)


1121-1121: Headings must start at the beginning of the line

(MD023, heading-start-left)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: coverage
  • GitHub Check: test
  • GitHub Check: go
🔇 Additional comments (14)
testdata/jwt/cases_es256kadr36.json (2)

4-4: Static analysis false positive—test JWT token.

The Gitleaks warning about a generic API key is a false positive. This is a test JWT token (header.payload.signature format), not a sensitive credential.


1-27: LGTM!

The test data structure is well-organized with clear descriptions and expected outcomes for both valid and invalid signature scenarios.

go/util/jwt/es256k_test.go (1)

63-63: LGTM!

The update correctly adopts the new verifier abstraction by using NewVerifier(s.pubKey, s.addr) instead of directly passing the public key. This aligns with the architectural change to introduce explicit verifier objects.

testdata/jwt/jwt.go (1)

9-9: LGTM!

Correctly adds the new ES256KADR36 test data file to the embedded filesystem, making it accessible via GetTestsFile.

go/util/jwt/suite_test.go (2)

10-10: LGTM!

The addition of addr and pubKey fields to the test suite correctly supports the new verifier abstraction, enabling tests to construct verifier objects via NewVerifier(pubKey, addr).

Also applies to: 24-25, 50-52


63-63: Consider enabling the ES256KADR36 test suite.

The ES256KADR36Test suite is commented out. If the implementation is ready, consider enabling it to ensure test coverage. If tests are unstable or incomplete, document the reason for disabling them.

Would you like me to help verify whether the ES256KADR36Test is ready to be enabled by examining the test implementation?

proto/node/akash/base/offchain/sign/sign.proto (1)

4-4: Static analysis false positive—gogoproto is a standard dependency.

The Buf warning about the missing gogoproto/gogo.proto import is a false positive. In Cosmos SDK projects, gogoproto is a standard, well-known dependency that's available during build. This import is valid.

go/util/jwt/verifier.go (1)

1-34: LGTM! Clean verifier abstraction.

This verifier abstraction is well-designed:

  • Clear interface with minimal surface area
  • Proper embedding of cryptotypes.PubKey for delegation
  • Compile-time interface compliance check
  • Simple, focused constructor

The abstraction provides a clean separation between verification concerns and key management.

docs/proto/provider.md (1)

1-1: Auto-generated docs—fix formatting in generator template
The markdown issues (indentation, heading alignment, link fragments) originate in the generator’s template (docs/protodoc-markdown.tmpl, used by script/protocgen-legacy.sh). Apply formatting fixes there so they propagate into provider.md rather than editing the generated file.

go/util/jwt/es256kadr36.go (2)

29-44: ES256KADR36 Sign flow looks correct

StdSignBytes + MsgSignData + SignByAddress aligns with ADR-36 off-chain signing. No blocking issues.


73-79: Registration of custom signing method LGTM

Alg() string and RegisterSigningMethod are correct; global var exposure is fine.

go/util/jwt/signer.go (1)

14-24: SignerI/Signer implementation is clean

Embedded keyring.Signer + GetAddress() is straightforward and fits the ES256KADR36 flow.

go/util/jwt/es256kadr36_test.go (2)

50-53: Helpers encodeSegment/decodeSegment are defined
The functions are implemented in es256k_test.go under the same package jwt, so they’re available in es256kadr36_test.go. No action needed.


46-48: Guard against nil signing method

Insert a nil check after jwt.GetSigningMethod to prevent panics:

 method := jwt.GetSigningMethod(tc.Expected.Alg)
+ require.NotNil(s.T(), method, "unknown signing method: %s", tc.Expected.Alg)
 sig, err := method.Sign(toSign, key)

Verify that your test fixtures don’t contain unknown alg values that could make GetSigningMethod return nil.

Comment on lines +10 to +16
var (
MsgTypeSignData = ""
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Initialize MsgTypeSignData directly instead of using reflection.

The empty string initialization followed by reflection in init() is unnecessarily complex. Consider initializing directly:

-var (
-	MsgTypeSignData = ""
-)
+const MsgTypeSignData = "MsgSignData"

This is clearer, performs better (compile-time constant vs. runtime reflection), and eliminates the dependency on init().

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In go/node/types/offchain/sign/sign.go around lines 10 to 12, replace the empty
string plus runtime reflection pattern by initializing MsgTypeSignData directly
as a constant string (e.g. set MsgTypeSignData = "sign/MsgSignData" or the exact
type URL/name you intend to use), remove the now-unnecessary init() reflection
code, and make MsgTypeSignData a package-level const or var initialized at
declaration so the value is available at compile time.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
go/node/types/offchain/sign/sign.go (1)

14-16: Make MsgTypeSignData a constant; avoid reflection

Initialize directly (compile-time) instead of via reflect in init.

-var (
-    MsgTypeSignData = ""
-)
+const MsgTypeSignData = "MsgSignData"
-
-func init() {
-    MsgTypeSignData = reflect.TypeOf(&MsgSignData{}).Elem().Name()
-}

Also applies to: 23-25

🧹 Nitpick comments (5)
go/util/jwt/verifier.go (1)

8-12: Minor naming consistency

Consider renaming Pubkey() → PubKey() for consistency with Cosmos naming.

testdata/jwt/cases_es256k.json (1)

4-4: Silence Gitleaks for test JWT fixtures

These tokens are test fixtures, not secrets. Add a Gitleaks allowlist for testdata/jwt/** to prevent false positives in CI.

Example gitleaks.toml rule:

[[rules]]
description = "Allow test JWTs"
id = "allow-test-jwts"
regex = '''eyJ[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+?\.[a-zA-Z0-9_-]+?'''
path = '''^testdata/jwt/'''
allowlist = { paths = ["testdata/jwt/"] }

Also applies to: 15-15, 28-28

go/util/jwt/es256k.go (1)

41-43: Tighten invalid key error message

Error still says “expects cryptotypes.PubKey” but Verify now expects VerifyI. Update message for clarity.

- return fmt.Errorf("%w: ES256K verify expects cryptotypes.PubKey", jwt.ErrInvalidKeyType)
+ return fmt.Errorf("%w: ES256K verify expects VerifyI", jwt.ErrInvalidKeyType)
go/util/jwt/es256kadr36.go (1)

46-47: Clarify invalid key type errors

Align error messages with expected interfaces (SignerI / VerifyI).

- return nil, fmt.Errorf("%w: ES256KADR36 sign expects cryptotypes.LedgerPrivKey", jwt.ErrInvalidKeyType)
+ return nil, fmt.Errorf("%w: ES256KADR36 sign expects SignerI", jwt.ErrInvalidKeyType)
@@
- return fmt.Errorf("%w: ES256KADR36 verify expects cryptotypes.PubKey", jwt.ErrInvalidKeyType)
+ return fmt.Errorf("%w: ES256KADR36 verify expects VerifyI", jwt.ErrInvalidKeyType)

Also applies to: 66-67

go/util/jwt/signer.go (1)

26-31: Accept narrower dependency in constructor

NewSigner only needs signing; take keyring.Signer instead of keyring.Keyring to reduce coupling and improve testability.

-func NewSigner(kr keyring.Keyring, addr sdk.Address) SignerI {
+func NewSigner(kr keyring.Signer, addr sdk.Address) SignerI {
 	return &Signer{
 		Signer: kr,
 		addr:   addr,
 	}
 }

Optional nits:

  • Consider renaming the struct field Signer to signer or backend to avoid confusion with the type name Signer.
  • Go style prefers Address() over GetAddress(); consider aligning if API is still fluid.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f7f673 and e8bdcb7.

⛔ Files ignored due to path filters (2)
  • go/inventory/v1/workloads.pb.go is excluded by !**/*.pb.go
  • go/node/types/offchain/sign/sign.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (12)
  • docs/proto/provider.md (2 hunks)
  • go/node/types/offchain/sign/sign.go (1 hunks)
  • go/util/jwt/es256k.go (1 hunks)
  • go/util/jwt/es256k_test.go (2 hunks)
  • go/util/jwt/es256kadr36.go (1 hunks)
  • go/util/jwt/jwt_test.go (6 hunks)
  • go/util/jwt/signer.go (1 hunks)
  • go/util/jwt/suite_test.go (3 hunks)
  • go/util/jwt/verifier.go (1 hunks)
  • proto/node/akash/base/offchain/sign/sign.proto (1 hunks)
  • testdata/jwt/cases_es256k.json (3 hunks)
  • testdata/jwt/cases_jwt.json.tmpl (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • testdata/jwt/cases_jwt.json.tmpl
🚧 Files skipped from review as they are similar to previous changes (1)
  • go/util/jwt/suite_test.go
🧰 Additional context used
🧬 Code graph analysis (6)
go/util/jwt/es256k.go (1)
go/util/jwt/verifier.go (1)
  • VerifyI (9-12)
go/util/jwt/es256k_test.go (2)
go/util/jwt/signer.go (1)
  • NewSigner (26-31)
go/util/jwt/verifier.go (2)
  • NewVerifier (21-26)
  • Verify (14-17)
go/util/jwt/jwt_test.go (3)
go/util/jwt/jwt.go (1)
  • Claims (90-96)
go/util/jwt/signer.go (2)
  • Signer (15-18)
  • NewSigner (26-31)
go/util/jwt/verifier.go (1)
  • NewVerifier (21-26)
go/util/jwt/es256kadr36.go (4)
go/util/jwt/signer.go (2)
  • SignerI (9-12)
  • Signer (15-18)
go/node/types/offchain/sign/sign.go (1)
  • StdSignBytes (61-86)
go/node/types/offchain/sign/sign.pb.go (3)
  • MsgSignData (27-32)
  • MsgSignData (36-36)
  • MsgSignData (37-39)
go/util/jwt/verifier.go (2)
  • Verify (14-17)
  • VerifyI (9-12)
go/util/jwt/signer.go (1)
go/testutil/ids.go (1)
  • Keyring (18-22)
go/node/types/offchain/sign/sign.go (1)
go/node/types/offchain/sign/sign.pb.go (3)
  • MsgSignData (27-32)
  • MsgSignData (36-36)
  • MsgSignData (37-39)
🪛 Buf (1.58.0)
proto/node/akash/base/offchain/sign/sign.proto

4-4: import "gogoproto/gogo.proto": file does not exist

(COMPILE)

🪛 Gitleaks (8.28.0)
testdata/jwt/cases_es256k.json

[high] 4-4: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


[high] 15-15: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)


[high] 28-28: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

🪛 LanguageTool
docs/proto/provider.md

[grammar] ~84-~84: There might be a mistake here.
Context: ... - akash/inventory/v1/workloads.proto - Workload ...

(QB_NEW_EN)


[grammar] ~85-~85: There might be a mistake here.
Context: ...ory/v1/workloads.proto) - Workload - [WorkloadReplica](#akash.inventory.v1.Wor...

(QB_NEW_EN)


[grammar] ~86-~86: There might be a mistake here.
Context: ...ory.v1.Workload) - WorkloadReplica - [WorkloadService](#akash.inventory.v1.Wor...

(QB_NEW_EN)


[grammar] ~87-~87: There might be a mistake here.
Context: ...WorkloadReplica) - WorkloadService - [WorkloadStatus](#akash.inventory.v1.Work...

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.18.1)
docs/proto/provider.md

84-84: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


85-85: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


86-86: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


87-87: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


88-88: Unordered list indentation
Expected: 2; Actual: 5

(MD007, ul-indent)


1067-1067: Headings must start at the beginning of the line

(MD023, heading-start-left)


1073-1073: Headings must start at the beginning of the line

(MD023, heading-start-left)


1080-1080: Link fragments should be valid

(MD051, link-fragments)


1090-1090: Headings must start at the beginning of the line

(MD023, heading-start-left)


1106-1106: Headings must start at the beginning of the line

(MD023, heading-start-left)


1121-1121: Headings must start at the beginning of the line

(MD023, heading-start-left)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: coverage
  • GitHub Check: go
🔇 Additional comments (2)
go/util/jwt/es256k_test.go (1)

58-76: Review comment incorrectly assumes string-based API
In jwt/v5, SigningMethod.Sign returns ([]byte, error) and Verify accepts []byte, so encodeSegment/decodeSegment usage is correct.

Likely an incorrect or invalid review comment.

go/util/jwt/jwt_test.go (1)

62-87: Do not remove encodeSegment; Sign returns raw bytes
SigningMethod.Sign returns []byte, so wrapping its output in encodeSegment(sig) to Base64URL-encode is correct—treating it as a pre-encoded string is invalid.

Likely an incorrect or invalid review comment.

Comment on lines +51 to +54
// GetSignBytes encodes the message for signing
func (m *MsgSignData) GetSignBytes() []byte {
return sdk.MustSortJSON(legacy.Cdc.MustMarshalJSON(m))
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Register MsgSignData with the legacy Amino codec (ADR‑36 compliance)

StdSignBytes/GetSignBytes rely on legacy.Cdc JSON. Without RegisterConcrete for MsgSignData under the expected name (commonly "sign/MsgSignData"), wallets (Keplr/Leap) won’t produce/verify ADR‑36 JSON consistently.

Add a legacy codec registration in this package (init or a RegisterLegacyAminoCodec function):

+import "github.com/cosmos/cosmos-sdk/codec"
+
+func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
+    cdc.RegisterConcrete(&MsgSignData{}, "sign/MsgSignData", nil)
+}
+
+func init() {
+    // Optional: also register on the global legacy codec if used in this lib
+    legacy.Cdc.RegisterConcrete(&MsgSignData{}, "sign/MsgSignData", nil)
+}

Then ensure your app/init calls RegisterLegacyAminoCodec on its codec. Based on learnings

Also applies to: 60-86

🤖 Prompt for AI Agents
In go/node/types/offchain/sign/sign.go around lines 51-54 (and similarly for
lines 60-86), MsgSignData is marshaled with legacy.Cdc but is not registered
with the legacy Amino codec; add a RegisterLegacyAminoCodec function (or an
init) in this package that calls legacy.Cdc.RegisterConcrete(&MsgSignData{},
"sign/MsgSignData", nil) (use the exact canonical name "sign/MsgSignData"),
export the function if you choose a RegisterLegacyAminoCodec pattern and ensure
the application init code calls it so wallets (Keplr/Leap) produce/verify ADR-36
JSON consistently.

syntax = "proto3";
package akash.base.offchain.sign;

import "gogoproto/gogo.proto";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix buf proto dependency for gogoproto

Buf cannot resolve gogoproto/gogo.proto. Add the buf dep (e.g., cosmos/gogo) or vendor the file so codegen doesn’t fail.

If you’re using buf, add to buf.yaml:

  • deps: ["buf.build/cosmos/gogo"]
    Or ensure your buf.work/buf.gen.yaml pull in the gogo module.

🏁 Script executed:

#!/bin/bash
set -e
echo "=== Buf config files ==="
find . -type f \( -name 'buf.yaml' -o -name 'buf.gen.yaml' -o -name 'buf.work.yaml' \)

echo -e "\n=== Snippet from sign.proto ==="
sed -n '1,20p' proto/node/akash/base/offchain/sign/sign.proto || echo "File not found"

echo -e "\n=== Searching for gogo.proto files ==="
find . -type f -name 'gogo.proto' || echo "No gogo.proto files found"

echo -e "\n=== Searching for gogoproto directories ==="
find . -type d -name 'gogoproto' || echo "No gogoproto directories found"

echo -e "\n=== Searching for 'cosmos/gogo' in Buf configs ==="
grep -R --include 'buf*.yaml' "cosmos/gogo" -n . || echo "No 'cosmos/gogo' references in Buf configs"

Length of output: 1042


Fix Buf config for gogoproto
Uncomment or add - buf.build/cosmos/gogo-proto under deps in proto/node/buf.yaml (and proto/provider/buf.yaml), or vendor gogoproto/gogo.proto locally so Buf can resolve the import.

🧰 Tools
🪛 Buf (1.58.0)

4-4: import "gogoproto/gogo.proto": file does not exist

(COMPILE)

🤖 Prompt for AI Agents
In proto/node/akash/base/offchain/sign/sign.proto around line 4, the import
"gogoproto/gogo.proto" cannot be resolved by Buf; update proto/node/buf.yaml and
proto/provider/buf.yaml to include the gogoproto dependency by adding or
uncommenting "- buf.build/cosmos/gogo-proto" under deps, then run buf mod
update, or alternatively vendor the gogoproto files into the repo (e.g., add
gogoproto/gogo.proto under a proto/vendor/gogoproto path and ensure the buf.yaml
`paths`/module configuration includes that vendor directory) so the import can
be resolved.

@troian troian merged commit baf66be into main Oct 15, 2025
13 of 15 checks passed
@troian troian deleted the jwt-adr-36 branch October 15, 2025 13:27
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants