fix(cookies): require domain and path together when url is absent
This commit is contained in:
@@ -181,6 +181,8 @@ flowchart TD
|
|||||||
- Reuse session state with `--session-name` for continuity.
|
- Reuse session state with `--session-name` for continuity.
|
||||||
- Keep locale/timezone consistent with target market.
|
- Keep locale/timezone consistent with target market.
|
||||||
- Use `--risk-mode block` in strict pipelines that require explicit operator intervention on verification pages.
|
- Use `--risk-mode block` in strict pipelines that require explicit operator intervention on verification pages.
|
||||||
|
- For `cookies set`, use either `--url <url>`, or `--domain <domain> --path <path>` together.
|
||||||
|
- If `--url`, `--domain`, and `--path` are all omitted, the cookie is scoped from the current page URL.
|
||||||
|
|
||||||
## Validation Scripts
|
## Validation Scripts
|
||||||
|
|
||||||
|
|||||||
+31
-14
@@ -828,6 +828,17 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result<Value, ParseError
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Playwright requires either `url` or a complete `domain`+`path` pair.
|
||||||
|
let has_url = cookie.get("url").is_some();
|
||||||
|
let has_domain = cookie.get("domain").is_some();
|
||||||
|
let has_path = cookie.get("path").is_some();
|
||||||
|
if !has_url && (has_domain != has_path) {
|
||||||
|
return Err(ParseError::MissingArguments {
|
||||||
|
context: "cookies set".to_string(),
|
||||||
|
usage: "When not using --url, you must provide both --domain <domain> and --path <path>",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Ok(json!({ "id": id, "action": "cookies_set", "cookies": [cookie] }))
|
Ok(json!({ "id": id, "action": "cookies_set", "cookies": [cookie] }))
|
||||||
}
|
}
|
||||||
"clear" => Ok(json!({ "id": id, "action": "cookies_clear" })),
|
"clear" => Ok(json!({ "id": id, "action": "cookies_clear" })),
|
||||||
@@ -2097,28 +2108,34 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cookies_set_with_domain() {
|
fn test_cookies_set_with_domain_requires_path() {
|
||||||
let cmd = parse_command(
|
let result = parse_command(
|
||||||
&args("cookies set mycookie myvalue --domain example.com"),
|
&args("cookies set mycookie myvalue --domain example.com"),
|
||||||
&default_flags(),
|
&default_flags(),
|
||||||
|
);
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_path_requires_domain() {
|
||||||
|
let result = parse_command(
|
||||||
|
&args("cookies set mycookie myvalue --path /api"),
|
||||||
|
&default_flags(),
|
||||||
|
);
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cookies_set_with_domain_and_path() {
|
||||||
|
let cmd = parse_command(
|
||||||
|
&args("cookies set mycookie myvalue --domain example.com --path /api"),
|
||||||
|
&default_flags(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(cmd["action"], "cookies_set");
|
assert_eq!(cmd["action"], "cookies_set");
|
||||||
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
||||||
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
||||||
assert_eq!(cmd["cookies"][0]["domain"], "example.com");
|
assert_eq!(cmd["cookies"][0]["domain"], "example.com");
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_cookies_set_with_path() {
|
|
||||||
let cmd = parse_command(
|
|
||||||
&args("cookies set mycookie myvalue --path /api"),
|
|
||||||
&default_flags(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(cmd["action"], "cookies_set");
|
|
||||||
assert_eq!(cmd["cookies"][0]["name"], "mycookie");
|
|
||||||
assert_eq!(cmd["cookies"][0]["value"], "myvalue");
|
|
||||||
assert_eq!(cmd["cookies"][0]["path"], "/api");
|
assert_eq!(cmd["cookies"][0]["path"], "/api");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -1486,8 +1486,8 @@ Operations:
|
|||||||
|
|
||||||
Cookie Set Options:
|
Cookie Set Options:
|
||||||
--url <url> URL for the cookie (allows setting before page load)
|
--url <url> URL for the cookie (allows setting before page load)
|
||||||
--domain <domain> Cookie domain (e.g., ".example.com")
|
--domain <domain> Cookie domain (use with --path, e.g., ".example.com")
|
||||||
--path <path> Cookie path (e.g., "/api")
|
--path <path> Cookie path (use with --domain, e.g., "/api")
|
||||||
--httpOnly Set HttpOnly flag (prevents JavaScript access)
|
--httpOnly Set HttpOnly flag (prevents JavaScript access)
|
||||||
--secure Set Secure flag (HTTPS only)
|
--secure Set Secure flag (HTTPS only)
|
||||||
--sameSite <Strict|Lax|None> SameSite policy
|
--sameSite <Strict|Lax|None> SameSite policy
|
||||||
@@ -1495,6 +1495,7 @@ Cookie Set Options:
|
|||||||
|
|
||||||
Note: If --url, --domain, and --path are all omitted, the cookie will be set
|
Note: If --url, --domain, and --path are all omitted, the cookie will be set
|
||||||
for the current page URL.
|
for the current page URL.
|
||||||
|
When --url is omitted, --domain and --path must be provided together.
|
||||||
|
|
||||||
Global Options:
|
Global Options:
|
||||||
--json Output as JSON
|
--json Output as JSON
|
||||||
|
|||||||
@@ -172,6 +172,14 @@ agent-browser storage local clear # Clear all
|
|||||||
agent-browser storage session # Same for sessionStorage
|
agent-browser storage session # Same for sessionStorage
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For `cookies set`, use one of these patterns:
|
||||||
|
|
||||||
|
- `--url <url>`
|
||||||
|
- `--domain <domain> --path <path>`
|
||||||
|
- omit all three to scope from the current page URL
|
||||||
|
|
||||||
|
When `--url` is omitted, `--domain` and `--path` must be provided together.
|
||||||
|
|
||||||
## Network
|
## Network
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -137,6 +137,20 @@ agent-browser state load auth.json
|
|||||||
agent-browser open https://app.example.com/dashboard
|
agent-browser open https://app.example.com/dashboard
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Cookie Injection for Auth Callbacks
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Before navigation: set by URL
|
||||||
|
agent-browser cookies set session_id "abc123" --url https://app.example.com/api/auth/sso/callback
|
||||||
|
|
||||||
|
# Explicit domain/path pair (must be provided together)
|
||||||
|
agent-browser cookies set auth_token "xyz789" --domain .example.com --path /api
|
||||||
|
|
||||||
|
# Or navigate first and rely on current URL
|
||||||
|
agent-browser open https://app.example.com/api/auth/sso/callback
|
||||||
|
agent-browser cookies set callback_token "token123"
|
||||||
|
```
|
||||||
|
|
||||||
### Session Persistence
|
### Session Persistence
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+12
-1
@@ -1378,9 +1378,20 @@ async function handleCookiesSet(
|
|||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
const page = browser.getPage();
|
const page = browser.getPage();
|
||||||
const context = page.context();
|
const context = page.context();
|
||||||
// Auto-fill URL for cookies that don't have domain/path/url set
|
// Playwright requires either `url` or a complete `domain` + `path` pair.
|
||||||
|
// If none are provided, we default to the current page URL.
|
||||||
const pageUrl = page.url();
|
const pageUrl = page.url();
|
||||||
const cookies = command.cookies.map((cookie) => {
|
const cookies = command.cookies.map((cookie) => {
|
||||||
|
const hasUrl = Boolean(cookie.url);
|
||||||
|
const hasDomain = Boolean(cookie.domain);
|
||||||
|
const hasPath = Boolean(cookie.path);
|
||||||
|
|
||||||
|
if (!hasUrl && hasDomain !== hasPath) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid cookie "${cookie.name}": provide either url, or both domain and path`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!cookie.url && !cookie.domain && !cookie.path) {
|
if (!cookie.url && !cookie.domain && !cookie.path) {
|
||||||
return { ...cookie, url: pageUrl };
|
return { ...cookie, url: pageUrl };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user