Skip to content
Draft
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
68 changes: 68 additions & 0 deletions .github/workflows/chatgpt-mobile-web-diagnostics.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: ChatGPT Mobile-Web Diagnostics

on:
workflow_dispatch:
push:
branches:
- agent/chatgpt-mobile-web-audit-v0-1
paths:
- .github/workflows/chatgpt-mobile-web-diagnostics.yml
- scripts/chatgpt_mobile_web_diagnostics.mjs
pull_request:
branches:
- main
paths:
- .github/workflows/chatgpt-mobile-web-diagnostics.yml
- scripts/chatgpt_mobile_web_diagnostics.mjs

permissions:
contents: read

concurrency:
group: chatgpt-mobile-diagnostics-${{ github.ref }}
cancel-in-progress: true

jobs:
diagnose:
name: Event lifecycle and login console detail
runs-on: ubuntu-latest
timeout-minutes: 10
env:
NPM_CONFIG_AUDIT: "false"
NPM_CONFIG_FUND: "false"

steps:
- name: Checkout exact revision
uses: actions/checkout@v6

- name: Install pinned browser driver
run: npm install --no-save --package-lock=false puppeteer-core@24.16.0

- name: Locate Chrome and validate script
id: runtime
shell: bash
run: |
set -euo pipefail
node --check scripts/chatgpt_mobile_web_diagnostics.mjs
chrome="$(command -v google-chrome-stable || command -v google-chrome || command -v chromium || command -v chromium-browser || true)"
test -n "${chrome}"
"${chrome}" --version
echo "chrome=${chrome}" >> "${GITHUB_OUTPUT}"

- name: Run focused passive diagnostics
shell: bash
run: |
set -euo pipefail
rm -rf reports/chatgpt-mobile-diagnostics
node scripts/chatgpt_mobile_web_diagnostics.mjs \
--chrome "${{ steps.runtime.outputs.chrome }}" \
--output-dir reports/chatgpt-mobile-diagnostics

- name: Upload exact diagnostic evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: chatgpt-mobile-web-diagnostics-${{ github.run_id }}
path: reports/chatgpt-mobile-diagnostics/
if-no-files-found: error
retention-days: 14
121 changes: 121 additions & 0 deletions .github/workflows/chatgpt-mobile-web-public.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: ChatGPT Public Mobile-Web Audit

on:
workflow_dispatch:
push:
branches:
- agent/chatgpt-mobile-web-audit-v0-1
paths:
- .github/workflows/chatgpt-mobile-web-public.yml
- audits/chatgpt/mobile-web-public.json
- scripts/chatgpt_mobile_web_public_observer.mjs
- docs/audits/CHATGPT_MOBILE_WEB_PUBLIC_AUDIT.md
- tests/test_chatgpt_mobile_web_public_audit.py
pull_request:
branches:
- main
paths:
- .github/workflows/chatgpt-mobile-web-public.yml
- audits/chatgpt/mobile-web-public.json
- scripts/chatgpt_mobile_web_public_observer.mjs
- docs/audits/CHATGPT_MOBILE_WEB_PUBLIC_AUDIT.md
- tests/test_chatgpt_mobile_web_public_audit.py

permissions:
contents: read

concurrency:
group: chatgpt-public-mobile-web-${{ github.ref }}
cancel-in-progress: true

jobs:
observe:
name: Passive signed-out mobile-web matrix
runs-on: ubuntu-latest
timeout-minutes: 15
env:
NPM_CONFIG_AUDIT: "false"
NPM_CONFIG_FUND: "false"

steps:
- name: Checkout exact revision
uses: actions/checkout@v6

- name: Validate bounded config
shell: bash
run: |
set -euo pipefail
config="audits/chatgpt/mobile-web-public.json"
python3 -m json.tool "${config}" >/dev/null
jq -e '
(.target_url == "https://chatgpt.com/") and
(.login_url == "https://chatgpt.com/auth/login") and
(.observation_ms <= 15000) and
((.profiles | length) == 5) and
(.boundaries.public_pages_only == true) and
(.boundaries.authenticated_testing == false) and
(.boundaries.message_submission == false) and
(.boundaries.login_submission == false) and
(.boundaries.file_upload == false) and
(.boundaries.microphone_permission == false) and
(.boundaries.camera_permission == false) and
(.boundaries.direct_application_api_testing == false) and
(.boundaries.fuzzing == false) and
(.boundaries.load_testing == false) and
(.boundaries.active_security_testing == false) and
(.boundaries.captcha_or_access_control_bypass == false) and
(.boundaries.private_data_collection == false)
' "${config}" >/dev/null

- name: Validate contract tests
shell: bash
run: |
set -euo pipefail
python3 - <<'PY'
import runpy

namespace = runpy.run_path("tests/test_chatgpt_mobile_web_public_audit.py")
tests = sorted(
(name, function)
for name, function in namespace.items()
if name.startswith("test_") and callable(function)
)
for name, function in tests:
function()
print(f"PASS {name}")
print(f"Validated {len(tests)} contract tests")
PY

- name: Install pinned browser driver
run: npm install --no-save --package-lock=false puppeteer-core@24.16.0

- name: Locate Chrome and validate observer
id: runtime
shell: bash
run: |
set -euo pipefail
node --check scripts/chatgpt_mobile_web_public_observer.mjs
chrome="$(command -v google-chrome-stable || command -v google-chrome || command -v chromium || command -v chromium-browser || true)"
test -n "${chrome}"
"${chrome}" --version
echo "chrome=${chrome}" >> "${GITHUB_OUTPUT}"

- name: Observe public home and login states
shell: bash
run: |
set -euo pipefail
rm -rf reports/chatgpt-mobile-web
node scripts/chatgpt_mobile_web_public_observer.mjs \
--config audits/chatgpt/mobile-web-public.json \
--chrome "${{ steps.runtime.outputs.chrome }}" \
--output-dir reports/chatgpt-mobile-web
cat reports/chatgpt-mobile-web/chatgpt-mobile-web-summary.md >> "${GITHUB_STEP_SUMMARY}"

- name: Upload exact public evidence
if: always()
uses: actions/upload-artifact@v4
with:
name: chatgpt-mobile-web-public-${{ github.run_id }}
path: reports/chatgpt-mobile-web/
if-no-files-found: error
retention-days: 14
73 changes: 73 additions & 0 deletions audits/chatgpt/mobile-web-diagnostics-result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"schema_version": "liminalqa-chatgpt-mobile-diagnostics-adjudication-v1",
"case_id": "chatgpt-mobile-web-public-2026-07-21",
"source": {
"repository": "safal207/LiminalQAengineer",
"pull_request": 106,
"exact_head": "e56e2e86770e4ed198380800d970a7198020d6e1",
"workflow_run_id": 29783766882,
"artifact_id": 8477666575,
"artifact_name": "chatgpt-mobile-web-diagnostics-29783766882",
"artifact_sha256": "dc76eadf08f34a03273f95aee2ff3a7256b39c1a600af5cef91c0c0fd799056c",
"packet_sha256": "545480af7621ee11a7c7bbaaca65c2d134791abab43cddddb1ae0a39a2357434"
},
"authority": {
"mode": "audit_only",
"authenticated_testing": false,
"prompt_submission": false,
"login_submission": false,
"direct_application_api_testing": false,
"access_control_bypass": false,
"security_claim": false,
"external_submission": false,
"merge": false
},
"adjudications": [
{
"id": "unauth-mweb-event-aborts",
"status": "REJECTED_FALSE_NETWORK_FAILURE",
"severity": "none",
"evidence": {
"rounds": 2,
"lifecycle_events_before_capture": [],
"page_view_response": 204,
"performance_response": 204,
"business_response": 204,
"statsc_flush_response": 200,
"cdp_terminal_signal": "net::ERR_ABORTED",
"timing": "Each successful HTTP response was followed within 0–33 ms by the CDP/Puppeteer requestfailed signal."
},
"decision": "The POSTs reached the first-party server and received successful HTTP responses before the browser loading-aborted signal. No pagehide, visibilitychange, beforeunload or unload event occurred before capture. The original generic failed-request detector must not count these as delivery failures."
},
{
"id": "mobile-login-console-error",
"status": "CONFIRMED_DIAGNOSTIC_USER_IMPACT_UNKNOWN",
"severity": "P3-diagnostic",
"evidence": {
"rounds": 2,
"elapsed_ms": [1284, 1010],
"console_type": "error",
"console_text": "JSHandle@error",
"serialized_values": [{}, "undefined"],
"source": "https://chatgpt.com/cdn/assets/2340486e-dndlwhxa5s7p8x6d.js",
"line": 27,
"column": 11836,
"stack_sources": [
"https://chatgpt.com/cdn/assets/2340486e-dndlwhxa5s7p8x6d.js:27:11836",
"https://chatgpt.com/cdn/assets/4813494d-fwc98srcx5jfpxqd.js:1:45686",
"https://chatgpt.com/cdn/assets/4813494d-fwc98srcx5jfpxqd.js:4:61078"
],
"page_errors": [],
"visible_login_failure": false
},
"decision": "A stable first-party console.error exists on the public mobile login page, but the logged object is not serializable through the current probe and no visible task failure is established. Preserve as a low-severity diagnostic finding, not a security or user-impact claim."
}
],
"recommended_repairs": [
"Update the generic network detector so a successful 2xx response followed by loadingFailed/ERR_ABORTED is not counted as a failed delivery without additional evidence.",
"In a first-party development environment, map the login bundle stack to source maps and log an explicit error code/message instead of an opaque Error object if the console.error is intentional.",
"Re-run the login probe after bundle changes and verify both console cleanliness and visible authentication options."
],
"verdict": "ONE_P3_DIAGNOSTIC_ONLY",
"verdict_meaning": "The mobile event signal is rejected as a detector false positive. One repeated public-login console diagnostic remains, with no demonstrated user impact."
}
Loading
Loading