Browse Source

test: cover the correct-password round trip for a form's password gate

form-password.json only asserted the closed prompt; nothing automated ever
submitted the right password and checked that the real form comes back. The
success path (webhook_controller.cpp's password check) returns the rendered
form directly in the same response that sets the auth cookie, so a single
POST with the right __form_password is enough to exercise it - no second
request or cookie carry-over needed for this part.

That request has to be application/x-www-form-urlencoded, not JSON or
multipart: cpp-httplib only fills req.params (what the password check reads
via req.has_param) from a urlencoded body. verify-node.py gains a "formBody"
spec option for this. form-password-correct.json submits the right password
and asserts the rendered form's field markup comes back, the password prompt
does not, and a Set-Cookie is issued.

What remains manual: the harness's "http" case type is a single request with
no cookie jar, so a second request that relies on the issued cookie to skip
the prompt on a later GET is not something this can express. That half of
the round trip - cookie issued now actually being honoured next time - is
still a manual check.
fszontagh 1 month ago
parent
commit
496eda5f08
2 changed files with 31 additions and 1 deletions
  1. 13 1
      scripts/verify-node.py
  2. 18 0
      tests/nodes/form-password-correct.json

+ 13 - 1
scripts/verify-node.py

@@ -10,6 +10,7 @@ import json
 import sys
 import time
 import urllib.error
+import urllib.parse
 import urllib.request
 
 BASE = "http://localhost:8090/api/v1"
@@ -63,7 +64,18 @@ def run_http_case(case, token, workflow_id):
     url = BASE.replace("/api/v1", "") + spec["path"].replace("{workflowId}", workflow_id)
     method = spec.get("method", "POST")
     multipart = spec.get("multipart")
-    if multipart:
+    form_body = spec.get("formBody")
+    if form_body is not None:
+        # application/x-www-form-urlencoded, not JSON - cpp-httplib only
+        # fills req.params (what handleWebhook's password check reads via
+        # req.has_param) from a urlencoded body. A JSON body never reaches
+        # that check, and multipart puts non-file parts in req.files instead
+        # of req.params, so neither can exercise the password gate's
+        # success path - only this can.
+        payload = urllib.parse.urlencode(form_body).encode()
+        req = urllib.request.Request(url, data=payload, method="POST")
+        req.add_header("Content-Type", "application/x-www-form-urlencoded")
+    elif multipart:
         boundary = "----smartboticverify"
         parts = []
         for name, value in multipart.get("fields", {}).items():

+ 18 - 0
tests/nodes/form-password-correct.json

@@ -0,0 +1,18 @@
+{
+  "name": "verify-form-password-correct",
+  "nodes": [
+    {"id": "n1", "name": "Form", "type": "form-trigger", "position": {"x": 0, "y": 0},
+     "config": {"title": "Private form", "password": "hunter2",
+                "fields": [{"name": "note", "label": "Note", "type": "text"}]}}
+  ],
+  "connections": [],
+  "http": {
+    "method": "POST",
+    "path": "/webhook/{workflowId}",
+    "formBody": {"__form_password": "hunter2"},
+    "expectStatus": 200,
+    "expectHeaders": {"Set-Cookie": "sb_form_"},
+    "expectBodyContains": ["name=\"note\""],
+    "expectBodyExcludes": ["This form is protected", "hunter2"]
+  }
+}