Skip to content

Hash history comments and sign them with the author's personal key.#6004

Merged
ChrisPenner merged 39 commits intotrunkfrom
cp/change-comments-sync
Jan 16, 2026
Merged

Hash history comments and sign them with the author's personal key.#6004
ChrisPenner merged 39 commits intotrunkfrom
cp/change-comments-sync

Conversation

@ChrisPenner
Copy link
Member

@ChrisPenner ChrisPenner commented Nov 14, 2025

Overview

Adds a migration which hashes and signs all of a codebase's history comments, as a step towards syncing them with Share.

Implementation approach and notes

Adds a Migration which:

  • Creates a Personal Key for the user.
    • A personal key is a randomly generated EdDSA public/private key pair which is stored in the user's credentials.json file.
    • This key can be used to assert the user's identity across code-servers in a cryptographically verifiable way.
  • Maps over all the user's history comments and hashes and signs them, we'll need the hash and author for syncing with share.
  • Extracts the credentials management into its own package, since we need to use it in the migration and can't depend on unison-cli there.
  • ensure hashing uses a canonicalized serialization of the components to ensure no hash-collisions that can result froma simple concatenation

Interesting/controversial decisions

It's hard to know whether personal keys are overkill or not, while it would likely be possible to get away with just Share auth in the short term, I don't think it's really sound in the presence of multiple codeservers; I opted to implement personal keys because I believe I'll get mileage out of them in the future, e.g. they can be used for things like service-account auth in CI and such.

Test coverage

  • Verify that the credentials.json is ported correctly.

I tested the migration by creating some comments on a trunk build and running the migration on it, then creating some new comments.

Loose ends

Next up is to implement the comment sync APIs.

@aryairani
Copy link
Contributor

We need a passphrase option here, right? Or what's the standard

@ChrisPenner
Copy link
Member Author

@aryairani

We need a passphrase option here, right? Or what's the standard

Hrmm, this is a deep rabbit hole to go down that adds a ton of work;

  • Do we support various keychains?
  • Yubikeys/physical devices?
  • Various password managers?
  • gpg agent?

I was planning on having ucm manage these complete for the user as basic EdDSA keys, rather than having the user configure their own keys; thus it's basically treated the same as your Share token, but with the added ability of cryptographic signing and a public key.

Do you think passphrases or the other mentioned features are table-stakes?

@ChrisPenner ChrisPenner force-pushed the cp/change-comments-sync branch 2 times, most recently from 37b15a0 to aa40862 Compare November 18, 2025 00:09
Copy link
Member Author

Choose a reason for hiding this comment

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

Part of the migration, this adds nullable versions of the new columns.

Copy link
Member Author

Choose a reason for hiding this comment

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

Part 3 of the migration, this makes the new columns non-nullable in SQLite's own annoying way, which is creating a new table and copying all the data between them, then dropping the original and renaming the new one.

Copy link
Member Author

Choose a reason for hiding this comment

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

This just moved due to import needs.

Copy link
Member Author

Choose a reason for hiding this comment

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

Some changes here to support the new comment hashes, author thumbprints, and author signatures.

Copy link
Member Author

@ChrisPenner ChrisPenner Nov 18, 2025

Choose a reason for hiding this comment

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

Now that migrations need a credential manager I rewrote the bulk of the credential manager stuff to support a proper singleton, which should be safer when multiple parts of the app may have their own credential managers; I also pulled it out into its own package so it can be accessed in the Migration.

Copy link
Member Author

Choose a reason for hiding this comment

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

All new Personal Key stuff.

A personal key is just a public-private EdDsa key pair, which is stored in the user's credentials.json file.

@ChrisPenner ChrisPenner force-pushed the cp/change-comments-sync branch from 28e1af1 to 0af09bd Compare December 19, 2025 16:18
@ChrisPenner ChrisPenner force-pushed the cp/change-comments-sync branch 2 times, most recently from 258064e to 6f4d4ac Compare January 6, 2026 18:40
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved into the unison-credentials package

- http-types
- ki
- lens
- lock-file
Copy link
Member Author

Choose a reason for hiding this comment

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

Moved into unison-credentials

@ChrisPenner ChrisPenner force-pushed the cp/change-comments-sync branch from abdb970 to 9b4a76e Compare January 7, 2026 00:08
@ChrisPenner ChrisPenner marked this pull request as ready for review January 7, 2026 00:09
@ChrisPenner ChrisPenner requested a review from aryairani January 7, 2026 00:12
@aryairani
Copy link
Contributor

aryairani commented Jan 7, 2026

it's basically treated the same as your Share token, but with the added ability of cryptographic signing and a public key.

Okay, makes sense. Sorry I just spotted your reply now.

Edit: It was a draft PR at the time so I feel less bad about not noticing the comment.

@aryairani
Copy link
Contributor

Hrmm, this is a deep rabbit hole to go down that adds a ton of work;

  • Do we support various keychains?
  • Yubikeys/physical devices?
  • Various password managers?
  • gpg agent?

Which approach does command-line ssh use?

Copy link
Contributor

@aryairani aryairani left a comment

Choose a reason for hiding this comment

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

after reverting the cabal hpack version lines (sorry) I would say it can be merged

@ChrisPenner
Copy link
Member Author

ChrisPenner commented Jan 8, 2026

@aryairani

Hrmm, this is a deep rabbit hole to go down that adds a ton of work;

  • Do we support various keychains?
  • Yubikeys/physical devices?
  • Various password managers?
  • gpg agent?

Which approach does command-line ssh use?

ssh does support encrypted keys of course, in SSH's case that key represents your ability to sign into remote servers,
in our case, currently the key is only used to signify the author of a comment.

If we're legitimately concerned about a user's credentials file being stolen or leaked then we shouldn't be storing unencrypted auth tokens on disk at all; since currently an attacker would just take the user's OAuth token rather than their personal key.

AFAIK storing unencrypted credentials is quite a common practice, e.g. the AWS cli just stores your unencrypted creds at ~/.aws/credentials; google does the same in ~/.config/gcloud/

Not saying it's bad to allow requiring a password for this stuff, and maybe if we end up using the personal key for accessing Unison Cloud we may wish to add more layers of security, but at the moment I don't think it's worth the time to implement, since if an attacker has access to your file-system we have bigger concerns than them fraudulently signing comments in your name;

Hrmm, Is that a reasonable stance?

@aryairani
Copy link
Contributor

Makes sense.
🤞 for CI

@sellout
Copy link
Contributor

sellout commented Jan 12, 2026

The Cabal smoke test failure seems like a simple one – need to add the new unison-credentials package to contrib/cabal.project.

The Weeder failures seem to be due to CI using Weeder 2.7.0 vs scripts/check.sh using Weeder 2.8.0 (see freckle/weeder-action/issues/146). I replicated it by changing the version of Weeder used locally, and got the same weeds.

  1. It doesn’t make sense to downgrade Weeder locally, because the weeds that 2.7.0 found aren’t real weeds – just a bug in older Weeder versions.
  2. Upgrading to GHC 9.6.6 with the current Nix infrastructure would be a major hassle for a minor fix.
  3. Replace Nix tooling & update toolchain #6046 will get scripts/check.sh and CI using the same Weeder (2.10.0), but is blocked on some optimization/benchmark work.

I suggest that this PR disable the Weeder check in CI. It‘ll be re-instated with the correct version when #6046 is merged. Independently, we can remove freckle/weeder-action in favor of running scripts/check-weeds in CI to avoid this sync issue in future.

@ChrisPenner ChrisPenner force-pushed the cp/change-comments-sync branch from f4e6821 to 4966a7b Compare January 15, 2026 20:52
@ChrisPenner ChrisPenner changed the base branch from trunk to topic/array-ops January 15, 2026 21:10
@ChrisPenner ChrisPenner requested a review from a team as a code owner January 15, 2026 21:10
@ChrisPenner ChrisPenner force-pushed the cp/change-comments-sync branch from cb0e671 to ef5feec Compare January 16, 2026 18:59
@ChrisPenner ChrisPenner merged commit ef5feec into trunk Jan 16, 2026
16 of 18 checks passed
@ChrisPenner ChrisPenner deleted the cp/change-comments-sync branch January 16, 2026 22:49
@ChrisPenner
Copy link
Member Author

It looks like this was merged red, but it was merged as part of a later branch that made it green ✅

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants