blastproof 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cli.js +19 -3
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -145,6 +145,8 @@ The agent is **forbidden from inventing values** — one it types must come from
|
|
|
145
145
|
|
|
146
146
|
The rule used to live only in the prompt, and a prompt instructs rather than enforces. Run against a real model, `fill the note field` did not fail — the agent made a value up, filled it, and the step **passed**, producing "This is a test note." on two runs and "This is a new note" on a third. A test going green over a value nobody wrote, differing between runs, is worse than a failure.
|
|
147
147
|
|
|
148
|
+
A placeholder counts as a source **only when the step names that variable**. `fill the password field with {{env.TEST_PASSWORD}}` works; `fill the password field` does not become valid because the agent supplies `{{env.SOMETHING}}` itself. An agent cannot know the name of a variable nobody showed it, so one it produces is a guess — and a guessed variable would put a live credential into a field your test never pointed one at, in output that cannot redact a secret it was never told about.
|
|
149
|
+
|
|
148
150
|
Two limits worth knowing. A value the page shows in one format and the field wants in another — `1234` in the step, `1,234.00` in the box — is refused, and the fix is to write the value the way it is typed. And a very short value (`3`) appears somewhere in almost any page, so it will pass; this closes fabricated content, not every fabricated character.
|
|
149
151
|
|
|
150
152
|
`run` also warns about it first — the same rule caught earlier, from the test file, on every path, before launching a browser or asking for a key:
|
package/dist/cli.js
CHANGED
|
@@ -509,7 +509,10 @@ async function performAction(page, action, ctx) {
|
|
|
509
509
|
var COMMIT_ACTIONS = /* @__PURE__ */ new Set(["click", "press"]);
|
|
510
510
|
var COMMIT_KEYS = /* @__PURE__ */ new Set(["Enter", "NumpadEnter", " ", "Space", "Spacebar"]);
|
|
511
511
|
var SOURCED_VALUE_ACTIONS = /* @__PURE__ */ new Set(["fill", "select"]);
|
|
512
|
-
|
|
512
|
+
function referencesOnlyNamedVars(value, step) {
|
|
513
|
+
const named = new Set(referencedEnvVars(step));
|
|
514
|
+
return referencedEnvVars(value).every((name) => named.has(name));
|
|
515
|
+
}
|
|
513
516
|
function normalise(text) {
|
|
514
517
|
return text.replace(/\s+/g, " ").trim().toLowerCase();
|
|
515
518
|
}
|
|
@@ -545,7 +548,16 @@ var StepRecovery = class {
|
|
|
545
548
|
* step — which is also the whole of the "does not cross steps" rule.
|
|
546
549
|
*/
|
|
547
550
|
readable;
|
|
551
|
+
/**
|
|
552
|
+
* The step exactly as written, for deciding which `{{env.*}}` variables it
|
|
553
|
+
* names (design env-placeholder-must-be-named, D3). Kept alongside the
|
|
554
|
+
* normalised copy rather than derived from it: `readable` is lowercased, and
|
|
555
|
+
* environment variable names are case-sensitive, so `TOKEN` and `token` must
|
|
556
|
+
* stay distinguishable in the one place that decides which secret gets typed.
|
|
557
|
+
*/
|
|
558
|
+
step;
|
|
548
559
|
constructor(step) {
|
|
560
|
+
this.step = step;
|
|
549
561
|
this.readable = [normalise(step)];
|
|
550
562
|
}
|
|
551
563
|
/**
|
|
@@ -614,7 +626,11 @@ var StepRecovery = class {
|
|
|
614
626
|
if (!SOURCED_VALUE_ACTIONS.has(action.action)) return void 0;
|
|
615
627
|
const value = action.value;
|
|
616
628
|
if (!value) return void 0;
|
|
617
|
-
if (
|
|
629
|
+
if (!referencesOnlyNamedVars(value, this.step)) {
|
|
630
|
+
const named = referencedEnvVars(this.step);
|
|
631
|
+
return `refused: the value "${value}" was NOT typed, because this step does not reference that {{env.*}} variable. ${named.length > 0 ? `This step references ${named.map((n) => `{{env.${n}}}`).join(", ")}.` : "This step references no environment variable."} A placeholder is a source only when the step names it \u2014 otherwise the test never asked for that secret to be typed here. Use a value this step supplies, or fail the step and say it supplies none.`;
|
|
632
|
+
}
|
|
633
|
+
if (referencedEnvVars(value).length > 0) return void 0;
|
|
618
634
|
const needle = normalise(value);
|
|
619
635
|
if (needle === "") return void 0;
|
|
620
636
|
if (this.readable.some((source) => source.includes(needle))) return void 0;
|
|
@@ -2990,7 +3006,7 @@ function parsePositiveNumber(flag) {
|
|
|
2990
3006
|
};
|
|
2991
3007
|
}
|
|
2992
3008
|
var program = new Command();
|
|
2993
|
-
program.name("blastproof").description("Open-source AI testing agent: plain-English YAML tests executed agentically on a real browser.").version("0.
|
|
3009
|
+
program.name("blastproof").description("Open-source AI testing agent: plain-English YAML tests executed agentically on a real browser.").version("0.15.0");
|
|
2994
3010
|
program.command("init").description("Scaffold .blastproof/ (config, tests, sample tests) in the current directory").action(async () => {
|
|
2995
3011
|
try {
|
|
2996
3012
|
const result = await initProject(process.cwd());
|