Skip to content

BUG1413418: Enable pybsn to connect to port 443 with the /a/api prefix#446

Open
Kinjal-Arista wants to merge 5 commits into
bigswitch:mainfrom
Kinjal-Arista:BUG1413418
Open

BUG1413418: Enable pybsn to connect to port 443 with the /a/api prefix#446
Kinjal-Arista wants to merge 5 commits into
bigswitch:mainfrom
Kinjal-Arista:BUG1413418

Conversation

@Kinjal-Arista

@Kinjal-Arista Kinjal-Arista commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Enables pybsn to automatically discover and connect to BigDB services that have been migrated to port 443 with the /a/api prefix
This PR is a follow-up after the previous PR ran into a bug. pybsn was updated to discover the new REST base URL on
port 443 as https://:443/a, but login still created the session cookie with path /api. That meant login could
succeed, while the next authenticated request to /a/api/... failed with 401 because the cookie was not sent. In CVML
this showed up as repeated pybsn client NOT connected polling until timeout.

This change derives the session cookie path from the base URL path prefix, so https://:443/a uses /a/api while
legacy URLs like https://:443 and https://:8443 continue to use /api.

Tested with unit tests and against a CVML controller with a custom script written using codex to utilise the new pybsn
to make a GET request to the controller:

  • old reverted version resolved https://10.226.78.185:443/a, set cookie path /api, and failed the first authenticated
    GET with 401
  • this version resolved https://10.226.78.185:443/a, set cookie path /a/api, and the same authenticated GET
    succeeded

Fixes: BUG1413418

Enables pybsn to automatically discover and connect to BigDB services
that have been migrated to port 443 with the /a/api prefix

Fixes: BUG1413418
Comment thread pybsn/__init__.py Outdated
Comment thread pybsn/__init__.py Outdated
Comment thread pybsn/__init__.py Outdated

@seamusarista seamusarista left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason argue wasn't able to the comments to github.

Argus Code Review Report

Review ID: 893fe51a
Platform: github
Identifier: #446
Team: bigswitch/pybsn
Mode: deep

Summary

Overview: This PR is a follow-up to a reverted change (CL 48851522 / CL 48954124) that adds port 443 with /a prefix support to pybsn. The key improvement over the reverted version is deriving the session cookie path from the base URL's path prefix, fixing the root cause of BUG-1889369 (401 auth failures due to cookie path /api not matching /a/api/... request paths). The implementation is well-structured: a new ApiEndpointConfig dataclass replaces the raw tuples, guess_url() gains URL parsing for schema-less inputs with explicit port or path prefix, and _attempt_login() dynamically computes the cookie path. Test coverage is comprehensive.

Key findings:

  • The core cookie-path fix is correct and directly addresses the root cause of the previous revert (BUG-1889369)
  • There is a usability gap: pybsn.connect("192.0.2.1:443", ...) (explicit port, no /a suffix) will fail to discover the API because the explicit-port branch doesn't auto-apply the /a prefix, while bare pybsn.connect("192.0.2.1", ...) works correctly
  • Naming issue: the ApiEndpointConfig.schema field should be scheme per RFC 3986; schema conflicts with the BigDB schema concept used throughout this codebase
  • Minor redundancy: urlparse(url) is called twice in _attempt_login() where one call would suffice

Context consulted:

  • Winnow: pybsn cookie handling and /a/api prefix
  • Bug: BUG-1413418 (RESOLVED/FIXED) — Move REST API on port 443 behind /a prefix
  • Bug: BUG-1889369 (RESOLVED/FIXED) — ZtnTest pybsn auth failure (401 on /a/api paths due to cookie path)
  • Bug: BUG-1418083 (NEW) — pybsn client support for port 443 with /a/ prefix

Comments (4 shown, severity ≥ low)

File: pybsn/__init__.py

[LOW] Line 561

Category: clarity

The field name schema should be scheme. In URL/HTTP terminology, the correct term is "scheme" (RFC 3986). Using schema here is confusing because schema already has a specific meaning in this codebase — BigDB schema (SCHEMA_PREFIX, client.schema(), etc.).

Suggested fix:

Rename the field to `scheme`:
```python
@dataclass(frozen=True)
class ApiEndpointConfig:
    scheme: str
    port_no: int
    prefix: str

And update the corresponding references in BIGDB_PROTO_PORTS and guess_url().


#### [MEDIUM] Line 589
**Category:** bug

When a user passes `"192.0.2.1:443"` (explicit port, no `/a` suffix), `parsed.path` is `""`, so the candidate URL becomes `https://192.0.2.1:443` without the `/a` prefix. The health check goes to `https://192.0.2.1:443/api/v1/auth/healthy` instead of `https://192.0.2.1:443/a/api/v1/auth/healthy`, causing discovery to fail with an exception. This is inconsistent with bare hostname behavior where `"192.0.2.1"` correctly probes port 443 with `/a`.

A user who knows their controller runs on port 443 and writes `pybsn.connect("192.0.2.1:443", ...)` will get a confusing failure.

**Suggested fix:**

When parsed.port is specified but parsed.path is empty, look up the default prefix from BIGDB_PROTO_PORTS for known ports:

if parsed.port is not None:
    schema = "https" if parsed.port in (443, 8443) else "http"
    prefix = parsed.path
    if not prefix:
        matching = [e for e in BIGDB_PROTO_PORTS if e.port_no == parsed.port]
        prefix = matching[0].prefix if matching else ""
    candidates = [(schema, parsed.hostname, parsed.port, prefix)]

#### [LOW] Lines 634-639
**Category:** style

`urlparse(url)` is called twice — once on line 634 to extract the path, and again on line 639 to extract the hostname. Store the result in a local variable to avoid the redundant parse.

**Suggested fix:**
parsed_url = urlparse(url)
url_path_prefix = parsed_url.path.rstrip("/")
session_cookie_path = f"{url_path_prefix}/api" if url_path_prefix else "/api"
session_cookie = requests.cookies.create_cookie(
    name="session_cookie",
    value=json_["session-cookie"],
    domain=parsed_url.hostname,
    path=session_cookie_path,
)

### File: `test/test_port_443_prefix.py`

#### [LOW] Line 230
**Category:** suggestion

This test is named `test_explicit_port_443_uses_https` but actually tests `"192.0.2.1:443/a"` (port + path prefix), not just `"192.0.2.1:443"`. A test for bare `"192.0.2.1:443"` (no `/a` suffix) is missing — this would document the expected behavior for that input and catch the discovery gap mentioned above.

**Suggested fix:**

Add a test for "192.0.2.1:443" without the /a suffix. Depending on the design decision, it should either auto-apply the /a prefix or clearly fail.

@Kinjal-Arista

Kinjal-Arista commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

For some reason argue wasn't able to the comments to github.

Argus Code Review Report

Review ID: 893fe51a Platform: github Identifier: #446 Team: bigswitch/pybsn Mode: deep

Summary

Overview: This PR is a follow-up to a reverted change (CL 48851522 / CL 48954124) that adds port 443 with /a prefix support to pybsn. The key improvement over the reverted version is deriving the session cookie path from the base URL's path prefix, fixing the root cause of BUG-1889369 (401 auth failures due to cookie path /api not matching /a/api/... request paths). The implementation is well-structured: a new ApiEndpointConfig dataclass replaces the raw tuples, guess_url() gains URL parsing for schema-less inputs with explicit port or path prefix, and _attempt_login() dynamically computes the cookie path. Test coverage is comprehensive.

Key findings:

  • The core cookie-path fix is correct and directly addresses the root cause of the previous revert (BUG-1889369)
  • There is a usability gap: pybsn.connect("192.0.2.1:443", ...) (explicit port, no /a suffix) will fail to discover the API because the explicit-port branch doesn't auto-apply the /a prefix, while bare pybsn.connect("192.0.2.1", ...) works correctly
  • Naming issue: the ApiEndpointConfig.schema field should be scheme per RFC 3986; schema conflicts with the BigDB schema concept used throughout this codebase
  • Minor redundancy: urlparse(url) is called twice in _attempt_login() where one call would suffice

Context consulted:

  • Winnow: pybsn cookie handling and /a/api prefix
  • Bug: BUG-1413418 (RESOLVED/FIXED) — Move REST API on port 443 behind /a prefix
  • Bug: BUG-1889369 (RESOLVED/FIXED) — ZtnTest pybsn auth failure (401 on /a/api paths due to cookie path)
  • Bug: BUG-1418083 (NEW) — pybsn client support for port 443 with /a/ prefix

Comments (4 shown, severity ≥ low)

File: pybsn/__init__.py

[LOW] Line 561

Category: clarity

The field name schema should be scheme. In URL/HTTP terminology, the correct term is "scheme" (RFC 3986). Using schema here is confusing because schema already has a specific meaning in this codebase — BigDB schema (SCHEMA_PREFIX, client.schema(), etc.).

Suggested fix:

Rename the field to `scheme`:
```python
@dataclass(frozen=True)
class ApiEndpointConfig:
    scheme: str
    port_no: int
    prefix: str

And update the corresponding references in BIGDB_PROTO_PORTS and guess_url().


#### [MEDIUM] Line 589
**Category:** bug

When a user passes `"192.0.2.1:443"` (explicit port, no `/a` suffix), `parsed.path` is `""`, so the candidate URL becomes `https://192.0.2.1:443` without the `/a` prefix. The health check goes to `https://192.0.2.1:443/api/v1/auth/healthy` instead of `https://192.0.2.1:443/a/api/v1/auth/healthy`, causing discovery to fail with an exception. This is inconsistent with bare hostname behavior where `"192.0.2.1"` correctly probes port 443 with `/a`.

A user who knows their controller runs on port 443 and writes `pybsn.connect("192.0.2.1:443", ...)` will get a confusing failure.

**Suggested fix:**

When parsed.port is specified but parsed.path is empty, look up the default prefix from BIGDB_PROTO_PORTS for known ports:

if parsed.port is not None:
    schema = "https" if parsed.port in (443, 8443) else "http"
    prefix = parsed.path
    if not prefix:
        matching = [e for e in BIGDB_PROTO_PORTS if e.port_no == parsed.port]
        prefix = matching[0].prefix if matching else ""
    candidates = [(schema, parsed.hostname, parsed.port, prefix)]

#### [LOW] Lines 634-639
**Category:** style

`urlparse(url)` is called twice — once on line 634 to extract the path, and again on line 639 to extract the hostname. Store the result in a local variable to avoid the redundant parse.

**Suggested fix:**
parsed_url = urlparse(url)
url_path_prefix = parsed_url.path.rstrip("/")
session_cookie_path = f"{url_path_prefix}/api" if url_path_prefix else "/api"
session_cookie = requests.cookies.create_cookie(
    name="session_cookie",
    value=json_["session-cookie"],
    domain=parsed_url.hostname,
    path=session_cookie_path,
)

### File: `test/test_port_443_prefix.py`

#### [LOW] Line 230
**Category:** suggestion

This test is named `test_explicit_port_443_uses_https` but actually tests `"192.0.2.1:443/a"` (port + path prefix), not just `"192.0.2.1:443"`. A test for bare `"192.0.2.1:443"` (no `/a` suffix) is missing — this would document the expected behavior for that input and catch the discovery gap mentioned above.

**Suggested fix:**

Add a test for "192.0.2.1:443" without the /a suffix. Depending on the design decision, it should either auto-apply the /a prefix or clearly fail.

Addressed all three suggestions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants