Fix API key changes not triggering container recreation
The container was only recreated when the auth mode changed, not when the API key value itself changed. This meant saving a new key required a manual container rebuild. Now we store a hash of the API key as a Docker label and compare it on start, so a key change automatically recreates the container (preserving the claude config volume). Also adds a note to the global AWS settings UI that changes require a container rebuild. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -169,6 +169,7 @@ pub async fn start_project_container(
|
||||
let needs_recreation = docker::container_needs_recreation(
|
||||
&existing_id,
|
||||
&project,
|
||||
api_key.as_deref(),
|
||||
settings.global_claude_instructions.as_deref(),
|
||||
&settings.global_custom_env_vars,
|
||||
)
|
||||
|
||||
@@ -10,6 +10,19 @@ use std::hash::{Hash, Hasher};
|
||||
use super::client::get_docker;
|
||||
use crate::models::{AuthMode, BedrockAuthMethod, ContainerInfo, EnvVar, GlobalAwsSettings, Project, ProjectPath};
|
||||
|
||||
/// Compute a fingerprint for the API key so we can detect when it changes
|
||||
/// without storing the actual key in Docker labels.
|
||||
fn compute_api_key_fingerprint(api_key: Option<&str>) -> String {
|
||||
match api_key {
|
||||
Some(key) => {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
key.hash(&mut hasher);
|
||||
format!("{:x}", hasher.finish())
|
||||
}
|
||||
None => String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute a fingerprint string for the custom environment variables.
|
||||
/// Sorted alphabetically so order changes do not cause spurious recreation.
|
||||
fn compute_env_fingerprint(custom_env_vars: &[EnvVar]) -> String {
|
||||
@@ -356,6 +369,7 @@ pub async fn create_container(
|
||||
labels.insert("triple-c.project-id".to_string(), project.id.clone());
|
||||
labels.insert("triple-c.project-name".to_string(), project.name.clone());
|
||||
labels.insert("triple-c.auth-mode".to_string(), format!("{:?}", project.auth_mode));
|
||||
labels.insert("triple-c.api-key-fingerprint".to_string(), compute_api_key_fingerprint(api_key));
|
||||
labels.insert("triple-c.paths-fingerprint".to_string(), compute_paths_fingerprint(&project.paths));
|
||||
labels.insert("triple-c.bedrock-fingerprint".to_string(), compute_bedrock_fingerprint(project));
|
||||
labels.insert("triple-c.image".to_string(), image_name.to_string());
|
||||
@@ -439,6 +453,7 @@ pub async fn remove_container(container_id: &str) -> Result<(), String> {
|
||||
pub async fn container_needs_recreation(
|
||||
container_id: &str,
|
||||
project: &Project,
|
||||
api_key: Option<&str>,
|
||||
global_claude_instructions: Option<&str>,
|
||||
global_custom_env_vars: &[EnvVar],
|
||||
) -> Result<bool, String> {
|
||||
@@ -477,6 +492,14 @@ pub async fn container_needs_recreation(
|
||||
}
|
||||
}
|
||||
|
||||
// ── API key fingerprint ─────────────────────────────────────────────
|
||||
let expected_api_key_fp = compute_api_key_fingerprint(api_key);
|
||||
let container_api_key_fp = get_label("triple-c.api-key-fingerprint").unwrap_or_default();
|
||||
if container_api_key_fp != expected_api_key_fp {
|
||||
log::info!("API key fingerprint mismatch, triggering recreation");
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// ── Project paths fingerprint ──────────────────────────────────────────
|
||||
let expected_paths_fp = compute_paths_fingerprint(&project.paths);
|
||||
match get_label("triple-c.paths-fingerprint") {
|
||||
|
||||
Reference in New Issue
Block a user