Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Notable changes between releases. Detailed migration notes for storage transitio

### Fixed

- **CLI help no longer prints callback signing secrets.** `awa serve --help` and `awa callbacks serve --help` identify `AWA_CALLBACK_HMAC_SECRET` without rendering its current value. Root help already keeps the manually resolved `DATABASE_URL` out of Clap output; regression coverage now protects all three credential-bearing help surfaces.

- **Nightly flake gates now carry runner-contention margin ([#399](https://github.com/hardbyte/awa/issues/399), [#434](https://github.com/hardbyte/awa/issues/434)).** Four assertion shapes in the chaos and benchmark suites were tight enough that shared-runner CPU contention failed them while every invariant they exist for was intact, eroding the 14-consecutive-green-nightlies release gate. `awa/tests/ci_timing.rs` now holds the scaling for all of them, and it only ever loosens a bound, and only when `CI` is set:
- The mixed-fleet chaos test set `heartbeat_staleness` to 250ms against a 50ms heartbeat interval. Under contention a *live* worker's heartbeat missed that window, so the runtime correctly rescued a healthy attempt and the test saw a genuine duplicate completion — a margin problem that read as a correctness bug. Chaos clients scale the staleness window via `scaled_staleness` while leaving the heartbeat and rescue *intervals* at chaos cadence, so the rescue path is still exercised.
- That test's assert-after-drain step watched both completion streams for a fixed 250ms quiet window, the same race [#335](https://github.com/hardbyte/awa/issues/335) fixed in `test_weight_proportionality`: a duplicate arriving at 251ms was missed, and on a slow runner the window expired while work was still moving. It now waits for the queue itself to reach a terminal state — the authoritative drain signal — then drains both streams with `try_recv`, so duplicate detection no longer depends on wall-clock timing.
Expand Down
4 changes: 2 additions & 2 deletions awa-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ enum Commands {
#[arg(long, default_value = "5", env = "AWA_CACHE_TTL")]
cache_ttl: u64,
/// Hex-encoded 32-byte key used to verify callback signatures.
#[arg(long, env = "AWA_CALLBACK_HMAC_SECRET")]
#[arg(long, env = "AWA_CALLBACK_HMAC_SECRET", hide_env_values = true)]
callback_hmac_secret: Option<String>,
/// Force the server into read-only mode regardless of DB privilege.
///
Expand Down Expand Up @@ -213,7 +213,7 @@ enum CallbackCommands {
pool_acquire_timeout: u64,
/// Hex-encoded 32-byte key used to verify callback signatures.
/// Required unless `--allow-unsigned` is set.
#[arg(long, env = "AWA_CALLBACK_HMAC_SECRET")]
#[arg(long, env = "AWA_CALLBACK_HMAC_SECRET", hide_env_values = true)]
callback_hmac_secret: Option<String>,
/// Path prefix the callback routes are mounted under. Defaults to
/// `/api/callbacks`, matching the built-in `awa serve` layout.
Expand Down
46 changes: 46 additions & 0 deletions awa-cli/tests/help_cli_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use assert_cmd::Command;

fn rendered_help(args: &[&str], env_name: &str, secret: &str) -> String {
let output = Command::cargo_bin("awa")
.expect("awa binary")
.env(env_name, secret)
.args(args)
.output()
.expect("run awa help command");

assert!(output.status.success());
format!(
"{}{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
)
}

#[test]
fn help_does_not_disclose_environment_database_url() {
let secret_url = "postgres://secret-user:secret-password@db.example/awa";
let rendered = rendered_help(&["--help"], "DATABASE_URL", secret_url);
assert!(rendered.contains("DATABASE_URL"));
assert!(!rendered.contains(secret_url));
assert!(!rendered.contains("secret-password"));
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

#[test]
fn serve_help_does_not_disclose_callback_secret() {
let secret = "serve-callback-secret-sentinel";
let rendered = rendered_help(&["serve", "--help"], "AWA_CALLBACK_HMAC_SECRET", secret);
assert!(rendered.contains("AWA_CALLBACK_HMAC_SECRET"));
assert!(!rendered.contains(secret));
}

#[test]
fn callback_receiver_help_does_not_disclose_callback_secret() {
let secret = "receiver-callback-secret-sentinel";
let rendered = rendered_help(
&["callbacks", "serve", "--help"],
"AWA_CALLBACK_HMAC_SECRET",
secret,
);
assert!(rendered.contains("AWA_CALLBACK_HMAC_SECRET"));
assert!(!rendered.contains(secret));
}