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 <noreply@anthropic.com>
This commit is contained in:
Joseph O'Brien
2026-04-01 21:19:23 -04:00
parent f80ea02f07
commit 58de007e19
4 changed files with 22 additions and 16 deletions

View File

@@ -2,7 +2,8 @@ use anyhow::{Context, Result};
use notcore::{HookPhase, Report, StepStatus}; use notcore::{HookPhase, Report, StepStatus};
use notfiles::{LinkOptions, link}; use notfiles::{LinkOptions, link};
use nothooks::{HookRunner, run_phase}; 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 serde::Deserialize;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@@ -88,8 +89,8 @@ pub fn run(opts: BootstrapOptions) -> Result<Report> {
} }
} }
// 4. Retrieve age key and install // 4. Resolve age identities
let sources: Vec<Box<dyn notsecrets::AgeKeySource>> = if let Some(kf) = opts.key_file { let sources: Vec<Box<dyn IdentitySource>> = if let Some(kf) = opts.key_file {
vec![Box::new(FileSource::new(kf))] vec![Box::new(FileSource::new(kf))]
} else { } else {
vec![ vec![
@@ -98,9 +99,8 @@ pub fn run(opts: BootstrapOptions) -> Result<Report> {
] ]
}; };
match resolve_age_key(sources) { match resolve_identities(sources) {
Ok(key) => { Ok(_identities) => {
install_age_key(&key)?;
report.add("age key", StepStatus::Ok); report.add("age key", StepStatus::Ok);
} }
Err(e) => { Err(e) => {

View File

@@ -45,7 +45,7 @@ fn main() -> Result<()> {
key_file, key_file,
dotfiles, dotfiles,
check_prereqs: Some(Box::new(prereqs::check_prerequisites)), check_prereqs: Some(Box::new(prereqs::check_prerequisites)),
env_injector: Some(Box::new(notsecrets::decrypt_sops)), env_injector: None,
}; };
let report = run(opts)?; let report = run(opts)?;
report.print(); report.print();

View File

@@ -19,7 +19,11 @@ fn make_test_env() -> TestEnv {
// age key file (content doesn't matter — FileSource reads it verbatim) // age key file (content doesn't matter — FileSource reads it verbatim)
let key_file = d.join("age.key"); 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 // notfiles.toml — one package "shell" targeting home tempdir
fs::write( fs::write(

View File

@@ -5,7 +5,8 @@ use tempfile::TempDir;
use notcore::{HookPhase, HookSpec}; use notcore::{HookPhase, HookSpec};
use notfiles::{LinkOptions, link}; use notfiles::{LinkOptions, link};
use nothooks::{HookResult, HookRunner}; 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 /// Test that notsecrets and nothooks can each be used independently
/// in the same integration boundary — resolving an age key from a file /// 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 // Write a fake age key via FileSource
let key_path = dir.path().join("age.key"); 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<Box<dyn AgeKeySource>> = vec![Box::new(FileSource::new(key_path))]; let sources: Vec<Box<dyn IdentitySource>> = vec![Box::new(FileSource::new(key_path))];
let key = resolve_age_key(sources).expect("resolve_age_key failed"); let identities = resolve_identities(sources).expect("resolve_identities failed");
assert!( assert!(!identities.is_empty(), "expected at least one identity");
key.trim().starts_with("AGE-SECRET-KEY-"),
"expected age key prefix, got: {key:?}"
);
// Write a hook that just prints // Write a hook that just prints
let script = dir.path().join("chain.nu"); let script = dir.path().join("chain.nu");