Skip to content

feat(auth): support private_key_jwt registration and authentication - #1379

Open
albertnusouo wants to merge 36 commits into
mainfrom
feat/app_registration_v3
Open

albertnusouo wants to merge 36 commits into
mainfrom
feat/app_registration_v3

Conversation

@albertnusouo

@albertnusouo albertnusouo commented Jun 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds app-secret-free client authentication for Lark/Feishu applications alongside the existing client_secret flow:

  • private_key_jwt uses a CLI-managed signing key.
  • private_key_jwt_local_keypair references a user-owned PEM whose public key is already registered for the app.

Both modes prove possession with RFC 7523 client assertions. They do not store or transmit an AppSecret. The actual private-key storage depends on the selected signer backend: a platform key store, an encrypted software key file, a verified external provider, or a referenced PEM file. client_secret remains the default authentication method.

Changes

  • Signer architecture (internal/keysigner, internal/keylesshelper)

    • Defines a stable signer interface with explicit key creation, lookup, signing, deletion, backend identity, and security level.
    • Default builds include OS-specific signers without feature tags:
      • macOS: Secure Enclave, then dedicated Keychain, through CGO-free purego Security.framework bindings.
      • Linux: TPM 2.0 through go-tpm.
      • Windows: native CNG Platform KSP and Software KSP.
    • Provides an encrypted software-file fallback and verified larksuite.keyless external-provider routing.
  • Key storage and references

    • Config stores authMethod plus a typed keyRef (source, provider, id) instead of an AppSecret.
    • Platform backends keep keys in their native stores and enforce non-exportability where supported.
    • software-file stores an AES-GCM-encrypted PKCS#8 private key protected by a random unlock secret held in the credential store.
    • The macOS Keychain backend uses a dedicated local keychain with its accompanying local password file.
    • --private-key-file references an existing user-owned PEM; the CLI does not copy or delete that file.
  • JWT signing (internal/auth/jwt)

    • Registration attestations carry the public JWK and its RFC 7638 thumbprint as kid.
    • Client assertions also carry kid, allowing the server to select the registered public key.
    • JWT construction remains implemented locally without adding a third-party JWT library.
  • Registration and CLI

    • lark-cli config init --new --private-key-jwt registers an app with a CLI-managed key.
    • lark-cli config init --app-id <app-id> --private-key-file <path> configures private_key_jwt_local_keypair for an already-registered public key.
    • Registration performs capability discovery, nonce-bound attestation, device authorization, brand discovery, and a post-save token probe.
    • Missing or unusable signer state fails closed instead of producing a configuration that cannot authenticate.
  • Token endpoints

    • Tenant tokens use the JWT bearer grant with client_assertion.
    • UAT device authorization, device-code token exchange, and refresh-token rotation authenticate with a fresh client assertion instead of client_secret.
    • client_secret remains supported and is still the default, while sharing some registration and token infrastructure with the new modes.
  • Config and diagnostics

    • Config resolution validates authMethod, key source, provider, and key identity before use.
    • auth status recognizes AppSecret-free applications.
    • doctor checks the configured signer and reports its backend and kid.
  • Build and dependencies

    • Release builds remain CGO_ENABLED=0; signer inclusion is selected by GOOS/GOARCH constraints, not custom build tags.
    • Adds direct dependencies required by the current backends: github.com/ebitengine/purego, github.com/google/go-tpm, and golang.org/x/crypto.

Compatibility and limitations

  • client_secret remains the default for existing configurations.
  • A PEM configured through --private-key-file must have its public key registered for the target app before running the command.
  • The current Lark WebSocket SDK requires an AppSecret, so long-running lark-cli event WebSocket connections are not supported by private-key JWT profiles.
  • “No AppSecret” does not mean no local key material: software and dedicated-keychain backends maintain protected local state as described above.

Test Plan

  • make build
  • make fmt-check
  • Focused tests for config, registration, JWT, signer backends, TAT, UAT device flow, and refresh flow
  • Local TLS-intercepting proxy E2E for both managed keys and user PEM:
    • registration attestation
    • tenant-token mint
    • UAT device authorization and device-code exchange
    • refresh-token rotation
    • server-side ES256 verification, RFC 7638 kid matching, unique jti, expected claims/TTL, and absence of client_secret
  • Full CI: the previous fast-gate failure was the unformatted cmd/doctor/doctor_test.go; fixed in 6515047f. GitHub checks for the latest commit are authoritative.

Related Issues

  • None

@coderabbitai

coderabbitai Bot commented Jun 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds secretless private_key_jwt end-to-end: keysigner contracts and registry, JWT attestation/assertion builders, app-registration auth-method negotiation, ClientAuth device-flow wiring, assertion-based TAT/UAT flows, config persistence and interactive selection, macOS keychain signer, and comprehensive tests.

Changes

Private Key JWT — Single Cohort

Layer / File(s) Summary
All changes (review checkpoint)
cmd/..., extension/keysigner/..., internal/auth/..., internal/credential/..., internal/core/..., cmd/config/..., sidecar/...
Complete set of changes encompassing keysigner contracts and registry, macOS keychain signer, JWT builders (attestation/client assertion), ClientAuth abstraction and application, app-registration init/begin/poll auth-method handling, device-flow migration to ClientAuth with context, assertion-based TAT (FetchTATWithAssertion) and UAT refresh changes, config init --auth-method wiring and persistence, diagnostics update, sidecar caller updates, and all associated tests.
  • Sequence Diagram(s): Included in the hidden review artifact above.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • larksuite/cli#235: Touches device_flow auth paths similar to RequestDeviceAuthorization/PollDeviceToken changes.
  • larksuite/cli#934: Related sidecar/demo device-flow bridge updates overlapping auth bridge wiring.

Suggested labels

feature, domain/base

Suggested reviewers

  • sang-neo03
  • liangshuo-1
  • MaxHuang22

"i am a rabbit, nibbling keys so bright,
signing tiny tokens through the night.
secrets left behind, the JWS hums true,
hop — the CLI speaks, auth flows through. 🐇"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 49.58% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(auth): support private_key_jwt registration and authentication' accurately captures the main change: adding RFC 7523 private_key_jwt support for registration and authentication.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description includes all required sections: Summary, Changes, Test Plan, and Related Issues. It clearly describes the scope, implementation, compatibility limits, and verification ste…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/app_registration_v3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot added the size/XL Architecture-level or global-impact change label Jun 10, 2026
@github-actions

github-actions Bot commented Jun 10, 2026 •

Copy link
Copy Markdown

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@f8f29fce1e66bef016a33d88ec84a70ea1cdbba8

🧩 Skill update

npx skills add larksuite/cli#feat/app_registration_v3 -y -g

@codecov

codecov Bot commented Jun 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 61.07314% with 1139 lines in your changes missing coverage. Please review.
✅ Project coverage is 76.39%. Comparing base (a079fd7) to head (bb0d0d9).

Files with missing lines Patch % Lines
internal/keylessprovider/provider.go 58.25% 115 Missing and 62 partials ⚠️
internal/keysigner/signer_tpm_linux.go 27.04% 113 Missing and 3 partials ⚠️
cmd/config/init_interactive.go 50.27% 79 Missing and 12 partials ⚠️
internal/keylesshelper/file.go 46.87% 61 Missing and 24 partials ⚠️
internal/keylesshelper/store.go 64.67% 45 Missing and 32 partials ⚠️
cmd/config/init.go 62.22% 57 Missing and 11 partials ⚠️
internal/keylesshelper/helper.go 55.97% 48 Missing and 11 partials ⚠️
internal/keysigner/signer_software.go 58.86% 34 Missing and 24 partials ⚠️
internal/keysigner/keysigner.go 77.15% 38 Missing and 15 partials ⚠️
internal/keysigner/public_key.go 62.40% 43 Missing and 7 partials ⚠️
... and 18 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1379      +/-   ##
==========================================
- Coverage   76.67%   76.39%   -0.29%     
==========================================
  Files        1126     1143      +17     
  Lines      129843   132627    +2784     
==========================================
+ Hits        99562   101324    +1762     
- Misses      22380    23113     +733     
- Partials     7901     8190     +289     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/config/init_interactive.go`:
- Around line 243-257: Add a short clarifying comment next to the init guard
that checks initResp.SupportedAuthMethods (the block starting with if
len(initResp.SupportedAuthMethods) > 0 && !slices.Contains(...)) describing that
an empty SupportedAuthMethods slice is intentionally treated as “older server /
unknown” and therefore allows the requested private_key_jwt to proceed (matching
resolveFinalAuthMethod’s back-compat behavior). Then add a unit test for
RequestAppRegistrationInit handling an empty SupportedAuthMethods array: mock
larkauth.RequestAppRegistrationInit to return SupportedAuthMethods: [] and
assert that the code path allows private_key_jwt (no rejection) and that the
comment’s documented behavior is covered; reference the init logic and
resolveFinalAuthMethod in the test to show alignment.

In `@extension/keysigner/signer_keychain_darwin.go`:
- Line 372: This file uses direct os.* filesystem calls (e.g., os.ReadFile at
the shown diff and additional uses of
ReadFile/WriteFile/Stat/MkdirAll/Remove/CreateTemp/Executable elsewhere in
signer_keychain_darwin.go) which violates the forbidigo rule; replace all these
os.X calls with the corresponding internal/vfs helpers (vfs.ReadFile,
vfs.WriteFile, vfs.Stat, vfs.MkdirAll, vfs.Remove, vfs.CreateTemp,
vfs.Executable) and import the internal/vfs package, ensuring each call site
(for example the function that reads key data where os.ReadFile(path) is used)
uses vfs.* instead; do not add a //nolint:forbidigo—migrate the calls instead to
satisfy lint/build checks.

In `@internal/auth/app_registration.go`:
- Around line 183-193: The fallback construction for verificationUriComplete
appends "?user_code=..." without handling existing query parameters; update the
logic in internal/auth/app_registration.go where verificationUriComplete is
built (variable verificationUriComplete, values verificationUri and userCode,
and ep.Open) to use the same query-joining logic as BuildVerificationURL: either
detect whether verificationUri (or base) contains a '?' and choose '?' vs '&'
accordingly, or better, construct the URL via net/url (url.URL and url.Values)
to add the user_code parameter safely so you never produce an invalid query
string when verification_uri already has parameters.

In `@internal/auth/jwt/jwt.go`:
- Around line 1-153: Add a unit test to jwt_test.go that triggers json.Marshal
failures by passing an unmarshalable value (e.g. a func or channel) in the
header or claims to exercise the error paths in buildSignedJWT; call
buildSignedJWT directly (or via SignClientAssertion/SignAttestation if you
prefer) with signer nil-check satisfied (use a stub signer) and assert the
returned error is non-nil and contains the marshal-related prefix ("jwt: marshal
header" or "jwt: marshal claims") so the test covers those failure branches.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b3a6a530-a2c3-42bb-9e6a-302a413baa72

📥 Commits

Reviewing files that changed from the base of the PR and between 7cc0b49 and dc3fe5a.

📒 Files selected for processing (30)
  • cmd/auth/login.go
  • cmd/auth/login_test.go
  • cmd/config/config_test.go
  • cmd/config/init.go
  • cmd/config/init_auth_method_test.go
  • cmd/config/init_interactive.go
  • extension/keysigner/keysigner.go
  • extension/keysigner/keysigner_test.go
  • extension/keysigner/registry.go
  • extension/keysigner/signer_keychain_darwin.go
  • extension/keysigner/signer_keychain_darwin_test.go
  • internal/auth/app_registration.go
  • internal/auth/app_registration_test.go
  • internal/auth/client_auth.go
  • internal/auth/client_auth_test.go
  • internal/auth/device_flow.go
  • internal/auth/device_flow_test.go
  • internal/auth/jwt/jwt.go
  • internal/auth/jwt/jwt_test.go
  • internal/auth/uat_client.go
  • internal/auth/uat_client_options_test.go
  • internal/core/config.go
  • internal/core/types.go
  • internal/core/types_test.go
  • internal/credential/default_provider.go
  • internal/credential/tat_fetch.go
  • internal/credential/tat_fetch_test.go
  • internal/credential/types.go
  • internal/identitydiag/diagnostics.go
  • sidecar/server-multi-tenant-demo/auth_bridge.go

Comment thread cmd/config/init_interactive.go Outdated
Comment thread extension/keysigner/signer_keychain_darwin.go Outdated
Comment thread internal/auth/app_registration.go
Comment thread internal/auth/jwt/jwt.go
@albertnusouo
albertnusouo force-pushed the feat/app_registration_v3 branch from 4d38935 to 7575d72 Compare June 10, 2026 11:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/core/config.go`:
- Around line 288-292: The resolver currently copies app.AuthMethod directly
into cfg (AuthMethod: app.AuthMethod) and only conditionally copies
app.KeyRef.ID, allowing unsupported auth methods and permitting private_key_jwt
without a key handle; update the resolution logic to validate and normalize
app.AuthMethod into cfg.AuthMethod (reject unknown values) and enforce that when
the resolved/auth method is "private_key_jwt" there is a non-nil app.KeyRef
(otherwise return an error during resolution), and add resolver unit tests
covering an invalid authMethod and the missing keyRef for private_key_jwt to
ensure failures occur at resolution time.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 387f9896-f74c-4cf0-987e-32b943a94f96

📥 Commits

Reviewing files that changed from the base of the PR and between 4d38935 and 7575d72.

📒 Files selected for processing (30)
  • cmd/auth/login.go
  • cmd/auth/login_test.go
  • cmd/config/config_test.go
  • cmd/config/init.go
  • cmd/config/init_auth_method_test.go
  • cmd/config/init_interactive.go
  • extension/keysigner/keysigner.go
  • extension/keysigner/keysigner_test.go
  • extension/keysigner/registry.go
  • extension/keysigner/signer_keychain_darwin.go
  • extension/keysigner/signer_keychain_darwin_test.go
  • internal/auth/app_registration.go
  • internal/auth/app_registration_test.go
  • internal/auth/client_auth.go
  • internal/auth/client_auth_test.go
  • internal/auth/device_flow.go
  • internal/auth/device_flow_test.go
  • internal/auth/jwt/jwt.go
  • internal/auth/jwt/jwt_test.go
  • internal/auth/uat_client.go
  • internal/auth/uat_client_options_test.go
  • internal/core/config.go
  • internal/core/types.go
  • internal/core/types_test.go
  • internal/credential/default_provider.go
  • internal/credential/tat_fetch.go
  • internal/credential/tat_fetch_test.go
  • internal/credential/types.go
  • internal/identitydiag/diagnostics.go
  • sidecar/server-multi-tenant-demo/auth_bridge.go
🚧 Files skipped from review as they are similar to previous changes (29)
  • cmd/auth/login_test.go
  • internal/core/types.go
  • cmd/config/config_test.go
  • sidecar/server-multi-tenant-demo/auth_bridge.go
  • internal/auth/uat_client_options_test.go
  • extension/keysigner/registry.go
  • internal/identitydiag/diagnostics.go
  • internal/credential/tat_fetch.go
  • internal/auth/uat_client.go
  • internal/credential/default_provider.go
  • extension/keysigner/signer_keychain_darwin_test.go
  • internal/auth/client_auth.go
  • extension/keysigner/keysigner.go
  • internal/core/types_test.go
  • internal/credential/tat_fetch_test.go
  • cmd/auth/login.go
  • internal/auth/device_flow_test.go
  • cmd/config/init_auth_method_test.go
  • internal/auth/client_auth_test.go
  • internal/auth/jwt/jwt.go
  • internal/credential/types.go
  • extension/keysigner/keysigner_test.go
  • internal/auth/app_registration_test.go
  • extension/keysigner/signer_keychain_darwin.go
  • internal/auth/device_flow.go
  • cmd/config/init_interactive.go
  • internal/auth/jwt/jwt_test.go
  • cmd/config/init.go
  • internal/auth/app_registration.go

Comment thread internal/core/config.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
internal/core/config_test.go (2)

159-192: ⚡ Quick win

Strengthen error assertions for consistency.

The test correctly validates both the failure case (missing KeyRef) and the success case (with KeyRef, verifying KeyLabel derivation). However, the error assertions only check the error type. Following the existing pattern at lines 110-112, consider also asserting that cfgErr.Hint and cfgErr.Message are non-empty to ensure users receive actionable error guidance.

📋 Proposed enhancement
 	var cfgErr *ConfigError
 	if !errors.As(err, &cfgErr) {
 		t.Fatalf("expected ConfigError, got %T: %v", err, err)
 	}
+	if cfgErr.Hint == "" {
+		t.Error("expected non-empty hint in ConfigError")
+	}
 
 	// Control: same config WITH a keyRef resolves cleanly and sets KeyLabel.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/core/config_test.go` around lines 159 - 192, In
TestResolveConfigFromMulti_PrivateKeyJWTRequiresKeyRef, after asserting the
error is a ConfigError via errors.As into cfgErr, add assertions to verify
cfgErr.Hint and cfgErr.Message are non-empty (e.g., use if cfgErr.Hint == "" {
t.Fatalf(...) } and similarly for cfgErr.Message) so the failure case from
ResolveConfigFromMulti yields actionable guidance; keep the checks consistent
with the existing pattern used elsewhere (see other tests that assert
cfgErr.Hint and cfgErr.Message).

135-157: ⚡ Quick win

Strengthen error assertions to match existing test pattern.

The test correctly validates that an unknown AuthMethod fails with a *ConfigError, but doesn't assert any of the error's fields. The existing pattern in this file (lines 110-112 in TestResolveConfigFromMulti_RejectsSecretKeyMismatch) also checks that cfgErr.Hint is non-empty. Consider asserting on Message and Hint to ensure the error provides actionable guidance and to improve regression protection.

📋 Proposed enhancement
 	var cfgErr *ConfigError
 	if !errors.As(err, &cfgErr) {
 		t.Fatalf("expected ConfigError, got %T: %v", err, err)
 	}
+	if cfgErr.Hint == "" {
+		t.Error("expected non-empty hint in ConfigError")
+	}
+	if cfgErr.Message == "" {
+		t.Error("expected non-empty message in ConfigError")
+	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/core/config_test.go` around lines 135 - 157, Update
TestResolveConfigFromMulti_RejectsUnknownAuthMethod to assert the returned
*ConfigError contains actionable fields: after confirming err is a *ConfigError
(cfgErr), add checks that cfgErr.Message and cfgErr.Hint are non-empty (or
otherwise validate expected substrings about unknown AuthMethod) so the test
mirrors the pattern used in TestResolveConfigFromMulti_RejectsSecretKeyMismatch
and guards against regressions in ResolveConfigFromMulti.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/core/config_test.go`:
- Around line 159-192: In
TestResolveConfigFromMulti_PrivateKeyJWTRequiresKeyRef, after asserting the
error is a ConfigError via errors.As into cfgErr, add assertions to verify
cfgErr.Hint and cfgErr.Message are non-empty (e.g., use if cfgErr.Hint == "" {
t.Fatalf(...) } and similarly for cfgErr.Message) so the failure case from
ResolveConfigFromMulti yields actionable guidance; keep the checks consistent
with the existing pattern used elsewhere (see other tests that assert
cfgErr.Hint and cfgErr.Message).
- Around line 135-157: Update
TestResolveConfigFromMulti_RejectsUnknownAuthMethod to assert the returned
*ConfigError contains actionable fields: after confirming err is a *ConfigError
(cfgErr), add checks that cfgErr.Message and cfgErr.Hint are non-empty (or
otherwise validate expected substrings about unknown AuthMethod) so the test
mirrors the pattern used in TestResolveConfigFromMulti_RejectsSecretKeyMismatch
and guards against regressions in ResolveConfigFromMulti.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 79e50d94-b61c-450a-b4a2-f0fd1aa4accf

📥 Commits

Reviewing files that changed from the base of the PR and between 29fa49f and 40de8a4.

📒 Files selected for processing (5)
  • cmd/config/init_auth_method_test.go
  • cmd/config/init_interactive.go
  • internal/auth/app_registration_test.go
  • internal/core/config.go
  • internal/core/config_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/core/config.go
  • internal/auth/app_registration_test.go
  • cmd/config/init_auth_method_test.go
  • cmd/config/init_interactive.go

@albertnusouo
albertnusouo force-pushed the feat/app_registration_v3 branch from 75910e8 to e6c8fd5 Compare June 13, 2026 08:52
@albertnusouo
albertnusouo force-pushed the feat/app_registration_v3 branch from 71be742 to 8c11b27 Compare July 11, 2026 10:19
@albertnusouo
albertnusouo force-pushed the feat/app_registration_v3 branch from 92df3c0 to 6918b52 Compare August 10, 2026 09:39
@CLAassistant

CLAassistant commented Aug 19, 2026 •

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
2 out of 3 committers have signed the CLA.

✅ JackZhao10086
✅ kiraWangRuilong
❌ albertnusouo
You have signed the CLA already but the status is still pending? Let us recheck it.

@albertnusouo
albertnusouo force-pushed the feat/app_registration_v3 branch from 47930a5 to 40560c8 Compare September 9, 2026 08:32
@kiraWangRuilong kiraWangRuilong added domain/auth Authentication subsystem and removed size/XL Architecture-level or global-impact change labels Sep 20, 2026
@github-actions github-actions Bot added size/XL Architecture-level or global-impact change and removed domain/auth Authentication subsystem labels Sep 20, 2026
@kiraWangRuilong
kiraWangRuilong force-pushed the feat/app_registration_v3 branch 5 times, most recently from 3044a3b to 6515047 Compare September 22, 2026 08:06
@kiraWangRuilong kiraWangRuilong added the domain/auth Authentication subsystem label Sep 22, 2026
@github-actions github-actions Bot removed the domain/auth Authentication subsystem label Sep 22, 2026
@kiraWangRuilong
kiraWangRuilong force-pushed the feat/app_registration_v3 branch 2 times, most recently from d0aff4e to bb0d0d9 Compare September 24, 2026 05:14
albertnusouo and others added 29 commits September 28, 2026 15:47
Replace the cgo Security.framework bindings with runtime FFI (ebitengine/purego)
so the keychain_signer builds with CGO_ENABLED=0 and cross-compiles for darwin
from any host. Same non-extractable-key security model (SecKeyCreateSignature on
an OS-held key). Release goes back to a single ubuntu runner; a macos-latest job
validates the FFI round-trip on real hardware as a release gate.
…build

Drop the keychain_signer build tag now that the signer is cgo-free
(purego runtime FFI). darwin builds always include it, so release and
PR-preview binaries are signed without a tag. Adjust go vet to
-unsafeptr=false for the FFI data-symbol dereference (golangci-lint
still runs full govet honoring the inline //nolint:govet).
- init_interactive.go: use errors.Is(err, huh.ErrUserAborted) instead of ==
  (the new auth-method picker path; comparison fails on wrapped errors)
- app_registration.go: wrap read-body error with %w instead of %v
sks's Windows COM dependency go-ole v1.2.5 has no arm64 VARIANT, so
building windows/arm64 with -tags sks_signer fails (undefined: VARIANT).
Mirror .goreleaser.yml's windows-arm64 build: ship arm64 without the TPM
signer (client_secret only). Other targets keep sks_signer.
The keychain signer lacked a HardwareProber, so probeHardware() returned
ok=false and doctor printed "no TEE signer in this build" on macOS — a
false negative, since the signer is registered and private_key_jwt works.
Implement ProbeHardware on keychainSigner (reports backend=keychain,
available when /usr/bin/security is present; no key access, no prompt) so
doctor shows 'keychain TEE available'.
…ault

Drop the sks_signer build tag, mirroring the darwin keychain signer: the
TPM signer now compiles into every linux and windows/amd64 build via
constraint //go:build linux || (windows && amd64) — no -tags needed.
windows/arm64 is arch-excluded (go-ole has no arm64 VARIANT) and falls
back to client_secret only.

- goreleaser: drop -tags=sks_signer; merge windows-arm64 into the windows
  build (amd64+arm64) since no tag is needed and arm64 is arch-excluded.
- build-pkg-pr-new.sh: remove tag logic.
- doctor: update the no-signer hint (signer ships by default on macOS,
  Linux, Windows/amd64).
- Switching from a custom tag to GOOS/GOARCH constraints also lets
  go mod tidy track sks/go-tpm/go-ole correctly.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL Architecture-level or global-impact change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants