refactor(secrets): epoch timestamps, a named list request, and unit tests

`SecretInfo` carries `created_at_millis` / `updated_at_millis` as `i64` rather
than RFC 3339 strings, matching `created_at_millis` elsewhere in the platform.
A caller comparing two timestamps no longer parses anything, and the PyO3 layer
hands Python integers instead of stringifying them. `updated_at_millis` is the
only observable that a rotation landed -- no API returns a credential -- so it
is worth being a number a caller can compare.

`RemoteListSecretsRequest` is declared alongside its response instead of being
an inline object built field by field, so a reader of one finds the other.

`function.rs` gains unit tests for the pure parts that had none: canonical JSON
sorts keys at every depth and leaves array order alone -- it is what the version
hash is taken over, so both matter -- floats are refused at any depth, and the
unknown-key check inspects only the level it is handed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UfmeJ533rQDnPBkMtjerV6
This commit is contained in:
Jonathan M Hsieh
2026-09-15 19:29:09 +00:00
co-authored by Claude Opus 5
parent 841edf1316
commit 7e55977dc7
6 changed files with 130 additions and 33 deletions
+4 -7
View File
@@ -804,17 +804,14 @@ impl Connection {
})
}
/// Name and timestamps as a plain mapping. `SecretInfo` carries no value,
/// so there is none to filter out here.
/// Name and timestamps as a plain tuple. `SecretInfo` carries no value, so
/// there is none to filter out here. Timestamps stay integers rather than
/// going through a string, so the caller can compare two without parsing.
pub fn describe_secret(self_: PyRef<'_, Self>, name: String) -> PyResult<Bound<'_, PyAny>> {
let inner = self_.get_inner()?.clone();
future_into_py(self_.py(), async move {
let info = inner.describe_secret(name).await.infer_error()?;
Ok(HashMap::from([
("name".to_string(), info.name),
("created_at".to_string(), info.created_at),
("updated_at".to_string(), info.updated_at),
]))
Ok((info.name, info.created_at_millis, info.updated_at_millis))
})
}