From 58de007e199f8daaabc6fa736796ed3e3a9d4314 Mon Sep 17 00:00:00 2001 From: Joseph O'Brien <98370624+89jobrien@users.noreply.github.com> Date: Wed, 1 Apr 2026 21:19:23 -0400 Subject: [PATCH] feat(notstrap): migrate to notsecrets age-native API, remove sops shell-out Replace AgeKeySource/resolve_age_key/install_age_key with IdentitySource/resolve_identities. Update integration tests to use a valid age bech32 key fixture. Co-Authored-By: Claude Sonnet 4.6 --- crates/notstrap/src/lib.rs | 12 ++++++------ crates/notstrap/src/main.rs | 2 +- tests/integration/tests/bootstrap.rs | 6 +++++- tests/integration/tests/cross_crate.rs | 18 ++++++++++-------- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/crates/notstrap/src/lib.rs b/crates/notstrap/src/lib.rs index fa9cd65..419cc1a 100644 --- a/crates/notstrap/src/lib.rs +++ b/crates/notstrap/src/lib.rs @@ -2,7 +2,8 @@ use anyhow::{Context, Result}; use notcore::{HookPhase, Report, StepStatus}; use notfiles::{LinkOptions, link}; use nothooks::{HookRunner, run_phase}; -use notsecrets::{BitwardenSource, FileSource, PromptSource, install_age_key, resolve_age_key}; +use notsecrets::{BitwardenSource, FileSource, PromptSource, resolve_identities}; +use notsecrets::sources::IdentitySource; use serde::Deserialize; use std::path::{Path, PathBuf}; @@ -88,8 +89,8 @@ pub fn run(opts: BootstrapOptions) -> Result { } } - // 4. Retrieve age key and install - let sources: Vec> = if let Some(kf) = opts.key_file { + // 4. Resolve age identities + let sources: Vec> = if let Some(kf) = opts.key_file { vec![Box::new(FileSource::new(kf))] } else { vec![ @@ -98,9 +99,8 @@ pub fn run(opts: BootstrapOptions) -> Result { ] }; - match resolve_age_key(sources) { - Ok(key) => { - install_age_key(&key)?; + match resolve_identities(sources) { + Ok(_identities) => { report.add("age key", StepStatus::Ok); } Err(e) => { diff --git a/crates/notstrap/src/main.rs b/crates/notstrap/src/main.rs index 1ffa517..3e87b5d 100644 --- a/crates/notstrap/src/main.rs +++ b/crates/notstrap/src/main.rs @@ -45,7 +45,7 @@ fn main() -> Result<()> { key_file, dotfiles, check_prereqs: Some(Box::new(prereqs::check_prerequisites)), - env_injector: Some(Box::new(notsecrets::decrypt_sops)), + env_injector: None, }; let report = run(opts)?; report.print(); diff --git a/tests/integration/tests/bootstrap.rs b/tests/integration/tests/bootstrap.rs index 6d4be53..fa7d84b 100644 --- a/tests/integration/tests/bootstrap.rs +++ b/tests/integration/tests/bootstrap.rs @@ -19,7 +19,11 @@ fn make_test_env() -> TestEnv { // age key file (content doesn't matter — FileSource reads it verbatim) let key_file = d.join("age.key"); - fs::write(&key_file, "AGE-SECRET-KEY-1TESTKEY\n").unwrap(); + fs::write( + &key_file, + "AGE-SECRET-KEY-1X3QKFQ4MZQM7LTJ3AX0N3EM63RGRV4J6N5ZDWPVKCEUCZKJWJSUSU6GYN6\n", + ) + .unwrap(); // notfiles.toml — one package "shell" targeting home tempdir fs::write( diff --git a/tests/integration/tests/cross_crate.rs b/tests/integration/tests/cross_crate.rs index 8ca2c9f..afbb030 100644 --- a/tests/integration/tests/cross_crate.rs +++ b/tests/integration/tests/cross_crate.rs @@ -5,7 +5,8 @@ use tempfile::TempDir; use notcore::{HookPhase, HookSpec}; use notfiles::{LinkOptions, link}; use nothooks::{HookResult, HookRunner}; -use notsecrets::{AgeKeySource, FileSource, resolve_age_key}; +use notsecrets::{FileSource, resolve_identities}; +use notsecrets::sources::IdentitySource; /// Test that notsecrets and nothooks can each be used independently /// in the same integration boundary — resolving an age key from a file @@ -16,14 +17,15 @@ fn test_nothooks_notsecrets_independent() { // Write a fake age key via FileSource let key_path = dir.path().join("age.key"); - fs::write(&key_path, "AGE-SECRET-KEY-1CROSSCRATE\n").unwrap(); + fs::write( + &key_path, + "AGE-SECRET-KEY-1X3QKFQ4MZQM7LTJ3AX0N3EM63RGRV4J6N5ZDWPVKCEUCZKJWJSUSU6GYN6\n", + ) + .unwrap(); - let sources: Vec> = vec![Box::new(FileSource::new(key_path))]; - let key = resolve_age_key(sources).expect("resolve_age_key failed"); - assert!( - key.trim().starts_with("AGE-SECRET-KEY-"), - "expected age key prefix, got: {key:?}" - ); + let sources: Vec> = vec![Box::new(FileSource::new(key_path))]; + let identities = resolve_identities(sources).expect("resolve_identities failed"); + assert!(!identities.is_empty(), "expected at least one identity"); // Write a hook that just prints let script = dir.path().join("chain.nu");