toga-ai 1.0.1208 → 1.0.1210
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/knowledge/INDEX.md
CHANGED
|
@@ -5,9 +5,9 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
5
5
|
## 1.0 framework
|
|
6
6
|
|
|
7
7
|
- **library** (Library) _(framework core)_ — 41 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
|
|
8
|
-
- **worker** (Worker) —
|
|
8
|
+
- **worker** (Worker) — 41 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
|
|
9
9
|
- **dbchanges** (Database Changes) _(framework core)_ — 1 doc(s) → [1.0/apps/dbchanges/INDEX.md](1.0/apps/dbchanges/INDEX.md)
|
|
10
|
-
- **worker1.5** (Worker 1.5) —
|
|
10
|
+
- **worker1.5** (Worker 1.5) — 10 doc(s) → [1.0/apps/worker1.5/INDEX.md](1.0/apps/worker1.5/INDEX.md)
|
|
11
11
|
- **togadesk** (TOGa Desk) — 19 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
|
|
12
12
|
- **togaview** (TOGa View) — 9 doc(s) → [1.0/apps/togaview/INDEX.md](1.0/apps/togaview/INDEX.md)
|
|
13
13
|
- **webhook** (Webhook) — 1 doc(s) → [1.0/apps/webhook/INDEX.md](1.0/apps/webhook/INDEX.md)
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Prudential: order email PDF attachments (which guide goes on which email)"
|
|
3
3
|
framework: "1.0"
|
|
4
|
-
repo:
|
|
5
|
-
project: Worker
|
|
4
|
+
repo: worker1.5
|
|
5
|
+
project: Worker 1.5
|
|
6
6
|
client: prudential
|
|
7
7
|
type: client-feature
|
|
8
8
|
status: active
|
|
9
|
-
updated: 2026-10-
|
|
9
|
+
updated: 2026-10-29
|
|
10
10
|
owners: ["bala"]
|
|
11
11
|
files:
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
12
|
+
- worker1.5/crons/toga2/prudential/generate_sales_and_purchase_orders_from_service_requests.php
|
|
13
|
+
- worker1.5/crons/toga2/prudential/transmissions_to_netsuite.php
|
|
14
|
+
- worker1.5/crons/toga2/prudential/transmit_ordershipped_updates_prudential.php
|
|
15
|
+
- worker1.5/crons/toga2/prudential/transmit_closecomplete_updates_prudential.php
|
|
16
|
+
- worker1.5/crons/toga2/prudential_beta/generate_sales_and_purchase_orders_from_service_requests.php
|
|
17
17
|
- store/common/prudential/home.php
|
|
18
18
|
related:
|
|
19
19
|
- transmit-ordershipped-email.md
|
|
@@ -61,31 +61,37 @@ All three live under `https://external-client-files.s3.us-west-2.amazonaws.com/p
|
|
|
61
61
|
|---|---|---|
|
|
62
62
|
| `EquipMe-Win11-Sep_2026_1.1.pdf` (since 2026-10-12; history: `v1` → `Sep_2026` → `Sep_2026_1.1`) | `Getting_Started_Guide_Windows11.pdf` | 2,762,485 B |
|
|
63
63
|
| `2026_Aug_PrudentialMacSetupGuide_ZCC.pdf` | `PrudentialMacSetupGuide.pdf` | 7,543,154 B |
|
|
64
|
-
| `Prudential_Instruction-2Page-V1.pdf
|
|
64
|
+
| `Prudential_DeviceReturnGuide_10-30-2026.pdf` (return guide, since 2026-10-29; was `Prudential_Instruction-2Page-V1.pdf`, 100,224 B) | (unchanged, same name) | 189,076 B |
|
|
65
65
|
|
|
66
66
|
A new-hire email (Win11 + Mac) is roughly **14 MB** once base64-encoded. Grepping for the attached-as filename will not find the S3 object, search the S3 basename.
|
|
67
67
|
|
|
68
68
|
**The attached name never changes, so it does not tell you the version.** The email shows `Getting_Started_Guide_Windows11.pdf` and the cron caches to `$cacheFolder/Getting_Started_Guide_Windows11.pdf` whatever URL was fetched. Check the byte size instead (Sep_2026_1.1 = 2,762,485; Sep_2026 = 2,735,276; v1 = 773,591). The old `EquipMe-Win11-v1.pdf` and the S3 object `Getting_Started_Guide_Windows11.pdf` are byte-identical (both the old guide).
|
|
69
69
|
|
|
70
70
|
### Swapping the Windows 11 guide: every hardcoded spot
|
|
71
|
-
Recurring task: Prudential sends a new EquipMe Windows 11 PDF from time to time (content or phone-number fixes). There is **no setting or table** for the guide URL. It is a literal in **12 `$pdfUrl2` lines across 5
|
|
71
|
+
Recurring task: Prudential sends a new EquipMe Windows 11 PDF from time to time (content or phone-number fixes). There is **no setting or table** for the guide URL. It is a literal in **12 `$pdfUrl2` lines across 5 worker1.5 files plus 2 store links**, and all must change together:
|
|
72
72
|
| File | Where |
|
|
73
73
|
|---|---|
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
77
|
-
| `
|
|
78
|
-
| `
|
|
74
|
+
| `worker1.5/crons/toga2/prudential/generate_sales_and_purchase_orders_from_service_requests.php` | `$pdfUrl2` in the order-created branches New (1), Refresh (3), and `else` (Breakfix/Swap/Label). Reclaim (5) attaches only the return guide. |
|
|
75
|
+
| `worker1.5/crons/toga2/prudential/transmit_ordershipped_updates_prudential.php` | Shipped (Dell, vendorId 1): new-hire block, plus the shared block inside `if ($reqType != 'Reclaim')`. |
|
|
76
|
+
| `worker1.5/crons/toga2/prudential/transmit_closecomplete_updates_prudential.php` | Delivered: same two places, same Reclaim guard. |
|
|
77
|
+
| `worker1.5/crons/toga2/prudential/transmissions_to_netsuite.php` | Shipped for Agilant-shipped POs (vendorId 2). Not scheduled on worker1.5, and prod has 0 vendor-2 POs with `c_dtEmailSentOrderShipped`, so it never fires today. Change it anyway. |
|
|
78
|
+
| `worker1.5/crons/toga2/prudential_beta/generate_sales_and_purchase_orders_from_service_requests.php` | Beta copy of order-created. |
|
|
79
79
|
| `store/common/prudential/home.php` (~L244-245) | Equip Me home page "Document" announcement: `$link` ("Click here") and `$win10Link` ("click here") both point at the guide. The Mac link (`$macLink`) is separate. |
|
|
80
80
|
|
|
81
81
|
Procedure:
|
|
82
82
|
1. Get the new PDF onto `s3://external-client-files/prudential/` under a **new** basename (never overwrite: the old name is what is live until deploy).
|
|
83
83
|
2. `curl -sI <new url>` must return **200**. A new upload can be private: on 2026-10-12 `EquipMe-Win11-Sep_2026_1.1.pdf` returned **403** while the old file returned 200. Fix the object ACL/policy before deploying (no AWS writes from Claude).
|
|
84
|
-
3. Branch from
|
|
85
|
-
4. One global find-replace of the old basename in `
|
|
84
|
+
3. Branch from the default branch in **both** `worker1.5` (`_main`) and `store` (`_production`).
|
|
85
|
+
4. One global find-replace of the old basename in `worker1.5/crons/toga2/prudential*` and `store/common/prudential/home.php` covers every spot. `grep` the old name after: expect 0 hits; new name: 12 in worker1.5, 2 in store.
|
|
86
86
|
5. Leave the Mac guide (`$pdfUrl4`, `2026_Aug_PrudentialMacSetupGuide_ZCC.pdf`) alone unless it is the one being swapped. Reclaim stays excluded.
|
|
87
87
|
|
|
88
|
-
Why step 2 matters: the crons fetch through `safeFetchPdf()`, which returns `false` on a 403, so a private file **silently drops the
|
|
88
|
+
Why step 2 matters: the crons fetch through `safeFetchPdf()`, which returns `false` on a 403, so a private file **silently drops the attachment** (and its sentence) from every email; nothing errors. The store link opens an S3 `AccessDenied` page.
|
|
89
|
+
|
|
90
|
+
### Swapping the return guide
|
|
91
|
+
Same steps 1, 2 and 4, with these differences:
|
|
92
|
+
- The basename is used **3 times per spot**: `$pdfUrl3`, the `$cacheFolder` path, and the `addAttachment()` name. The customer sees the S3 basename (no rename on attach).
|
|
93
|
+
- **24 hits in 5 worker1.5 files**: order-created 9 (3 branches), shipped 3 + 3 (both shipped crons), delivered 3, beta order-created 6.
|
|
94
|
+
- `store` has no return-guide link (0 hits in `home.php`), so only `worker1.5` changes.
|
|
89
95
|
|
|
90
96
|
### The verbiage has to match what actually attached
|
|
91
97
|
Every attach is guarded by `if ($pdfGuideX !== false)`, but until 2026-08-31 the `$attachmentText` paragraph that *describes* the attachments was unconditional. A failed S3 fetch produced an email whose copy pointed the recipient at guides not on the message — and it always said "guides" plural even when a single guide attached. The rule now, in every branch touched: **derive the sentence from the guards, not from the intent.**
|
|
@@ -130,7 +136,7 @@ No committed harness. Build a throwaway `test_<x>_emails.php` next to the cron,
|
|
|
130
136
|
## Gotchas
|
|
131
137
|
- **`transmit_closecomplete_updates_prudential.php` still over-promises (~line 447).** Its delivered email hardcodes "Guides for Windows 11 and MacBook devices are provided" with no reference to whether either PDF actually attached — the exact bug fixed everywhere else on 2026-08-31. Left alone deliberately to keep PR #1707's diff to files already being changed. **Worth a follow-up ticket.**
|
|
132
138
|
- **`transmissions_to_netsuite.php` also sends *delivered* emails — with no attachments at all.** It carries its own "New hire equipment has been delivered" / "Your equipment has been delivered" blocks (~L1765 and ~L2149) that make **zero** `addAttachment()` calls, while `transmit_closecomplete_updates_prudential.php` sends the **same two subjects** with the guides attached. **Whether both fire for the same order was not established** — if they do, the recipient gets a duplicate delivered email, one attachment-less. Check this before changing either.
|
|
133
|
-
- **`prudential_beta/` does not match prod.** `crons/toga2/prudential_beta/generate_sales_and_purchase_orders_from_service_requests.php` is `active: 1` on the same schedule but points at the beta DB and still references the
|
|
139
|
+
- **`prudential_beta/` does not match prod.** `crons/toga2/prudential_beta/generate_sales_and_purchase_orders_from_service_requests.php` is `active: 1` on the same schedule but points at the beta DB and still references the old `PrudentialMacSetupGuide.pdf` (not the `_ZCC` one). **A beta test will not reproduce prod Mac-guide behavior.** The Win11 guide (2026-10-05) and the return guide (2026-10-29) are kept in sync with prod; the Mac guide is left as-is on purpose.
|
|
134
140
|
- **Breakfix / Swap / Label get no Mac guide on the order-created email** (they do get it on shipped and delivered). Known, and left alone on purpose — not a bug to "fix" unasked.
|
|
135
141
|
- The delivered cron (`transmit_closecomplete_updates_prudential.php`) already followed the rule and was deliberately **not** touched.
|
|
136
142
|
|
|
@@ -140,6 +146,7 @@ No committed harness. Build a throwaway `test_<x>_emails.php` next to the cron,
|
|
|
140
146
|
- [App_Email Side Effects & Test Mode](../../../1.0/apps/library/features/email-test-mode-and-write-free-sends.md)
|
|
141
147
|
|
|
142
148
|
## Change history
|
|
149
|
+
- 2026-10-29 — Return guide swapped `Prudential_Instruction-2Page-V1.pdf` → `Prudential_DeviceReturnGuide_10-30-2026.pdf` in all 24 spots, beta included; file paths now worker1.5 (TRUE-83422) (bala)
|
|
143
150
|
- 2026-10-23 — Schedule now `worker1.5/schedules/cron.worker.json`; linked the new order-email-recipients doc (TRUE-83157) (bala)
|
|
144
151
|
- 2026-10-12 — Win11 guide swapped `Sep_2026` → `Sep_2026_1.1` (phone number change); added swap procedure + S3 403 check (bala)
|
|
145
152
|
- 2026-10-05 — Win11 guide swapped `v1` → `Sep_2026` in all 12 cron spots + Equip Me page (bala)
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: session
|
|
3
|
+
slug: saml-signature-checks
|
|
4
|
+
title: TRUE-83199 Turn on SAML signature checks — scoping
|
|
5
|
+
author: amadda
|
|
6
|
+
repos: [saml, _underscore, dbchanges2]
|
|
7
|
+
framework: "2.0"
|
|
8
|
+
client: shared
|
|
9
|
+
status: active
|
|
10
|
+
created: 2026-10-29
|
|
11
|
+
updated: 2026-10-29
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Session: saml-signature-checks
|
|
15
|
+
**Date:** 2026-10-29
|
|
16
|
+
**Project/Repo:** saml + _underscore + dbchanges2 (2.0)
|
|
17
|
+
**Task:** Scope TRUE-83199 — make the saml gateway `/acs` check the IdP signature (plus Issuer, Audience, Destination, time window, RelayState client) per client, using new columns on `Core.ClientAuthentications_Sso`. No code written yet; this session was walk-through and agreement only.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## What WORKED
|
|
22
|
+
- Confirmed the gap in code: `saml/Controller/Index.php:414-415` checks only `StatusCode === STATUS_SUCCESS`. The signature check (lines 313-412) is commented-out test code with hardcoded certs, RSA_SHA1, ending in `exit`.
|
|
23
|
+
- Git history: the signature test code was added already commented out in `4bcee38` (2024-08-29, "Final changes for Compass SAML"). It was never live.
|
|
24
|
+
- Package: `litesaml/lightsaml` 3.0.3 (+ `robrichards/xmlseclibs` 4.0.0). LightSaml has a built-in signature check (`getSignature()->validate($key)`), so no new library is needed.
|
|
25
|
+
- Decoded the saved Compass test response (`Index.php:245`, inside the comment block): signed twice (Response + Assertion) with RSA-SHA256, Issuer `https://sso.compassmanager.com`, Audience `https://compass.togacommerce.com/?meta`, Destination `https://compass.togacommerce.com/?acs` (old URL), 30-second time window.
|
|
26
|
+
- `entityIdentifier` meaning resolved: it is OUR SP name (sent as `<Issuer>` in our AuthnRequest, `_underscore/Model/Core/ClientAuthentication.php:118`) — except Rate's rows, which hold Rate's IdP metadata URL.
|
|
27
|
+
- ACS URL is built in code, not stored: `samlHostUrl(env) . '/acs'` (`ClientAuthentication.php:6-11,106`). Prod = `https://saml.togahub.com/acs`. One shared `/acs` for all clients; client found by RelayState domain uuid.
|
|
28
|
+
- `/meta` publishes `WantAssertionsSigned="true"` but `/acs` never checks — code does not match what we promise.
|
|
29
|
+
- Read-only queries on `client-sandbox` Core: SSO rows = Compass Group (production, sandbox-client), CompassCanada (production, sandbox-client), Rate (production, beta), True (production). 46 clients total; SSO 4, LOGIN 1, ACTIVE_DIRECTORY 1.
|
|
30
|
+
- User lookup: `_Model_<Client>_ClientAuthentication::getAuthenticatedSsoUser()` (Compass/Rate/True in `_underscore/Model/<Client>/ClientAuthentication.php`) only matches NameID to an active user.
|
|
31
|
+
- Found: Compass `getAuthenticatedSsoUser()` maps any NameID containing `@togatech.com` to fixed user 4273. In client-sandbox `Client_Compass`, 4273 is active with roles Base, Admin, SuperUser, Compass Base, Manager, Refresh Orders (6 of 16).
|
|
32
|
+
|
|
33
|
+
## What did NOT work — DO NOT RETRY THESE
|
|
34
|
+
- Read-only `toga_query` on `prod` Core (SSO client list) was denied by the Claude Code auto-mode classifier ("The server-side auto mode classifier judged this action dangerous"). Developer said to use sandbox (`client-sandbox`) instead, read-only only.
|
|
35
|
+
- start gate blocked the ticket-reader agent and `cat` during the primer stage; read the earlier session's ticket JSON with the Read tool instead.
|
|
36
|
+
- zsh: unquoted `--include=*.php` fails with "no matches found" — quote it.
|
|
37
|
+
|
|
38
|
+
## Not tried yet (candidates for next session)
|
|
39
|
+
- Local proof of the hole (dev `http://saml` only, never sandbox/prod): fake SAMLResponse (Success + real username, no signature, encrypted to our public encryption cert) + real RelayState → POST `/acs`. Doubles as the regression test.
|
|
40
|
+
- Check prod: SSO client list and whether user 4273 in prod Compass also has Admin/SuperUser (needs permission or a teammate).
|
|
41
|
+
- Find which Destination/ACS URL each IdP uses today (server access logs), since a Sept 2025 fix `1bc6c37` handles legacy `/?acs`.
|
|
42
|
+
- Get IdP metadata (cert + entity ID) for Compass, CompassCanada, Rate (prod + beta), True, Compass sandbox.
|
|
43
|
+
- CTO second opinion before finalizing approach (schema change + auth change).
|
|
44
|
+
|
|
45
|
+
## Current file state
|
|
46
|
+
| File | Status | Notes |
|
|
47
|
+
|------|--------|-------|
|
|
48
|
+
| ~/.claude/projects/-Users-amadda-Desktop-Projects-saml/memory/user-walk-through-before-building.md | created | personal habit note |
|
|
49
|
+
| ~/.claude/projects/-Users-amadda-Desktop-Projects-saml/memory/user-communication-profile.md | created | max 2 simple bullets per reply |
|
|
50
|
+
| ~/.claude/projects/-Users-amadda-Desktop-Projects-saml/memory/MEMORY.md | modified | index lines |
|
|
51
|
+
| (no app repo files changed) | — | saml + dbchanges2 are on branch TRUE-83199; _underscore not switched yet |
|
|
52
|
+
|
|
53
|
+
## Decisions made
|
|
54
|
+
- Plan agreed (high level), numbered:
|
|
55
|
+
1. Capture the response at `/acs`.
|
|
56
|
+
2. Check the signature with the client's saved `idpSigningCertificate` (never the cert inside the response).
|
|
57
|
+
3. Compare `<Issuer>` with saved `idpEntityIdentifier`.
|
|
58
|
+
4. Check Audience/Destination = our URLs, NotBefore/NotOnOrAfter valid, RelayState client = SSO row's client.
|
|
59
|
+
5. On failure: `LOG_ONLY` logs and lets in; `ENFORCE` blocks.
|
|
60
|
+
- Add 3 columns to `Core.ClientAuthentications_Sso`: `idpEntityIdentifier`, `idpSigningCertificate`, `signatureMode` (LOG_ONLY / ENFORCE). Rationale: per-client cert storage; safe rollout. Rejected: turning the old commented code back on (hardcoded certs, SHA1, `exit`).
|
|
61
|
+
- Do not store responses in the DB. Log per-check pass/fail + Issuer, Destination, signing method to Sentry/error_log; never the full response (user data).
|
|
62
|
+
- Keep the shared `/acs` (no per-client ACS URLs) — changing would force every client to reconfigure their IdP.
|
|
63
|
+
- Use LightSaml's built-in signature validation, not hand-written xmlseclibs code.
|
|
64
|
+
|
|
65
|
+
## Blockers
|
|
66
|
+
- Open questions for the developer / team:
|
|
67
|
+
1. Put `_underscore` on branch TRUE-83199 (model needs the 3 new fields)?
|
|
68
|
+
2. Who gets IdP metadata/certs from Compass, CompassCanada, Rate, True?
|
|
69
|
+
3. Ticket misses CompassCanada and Rate beta — add them?
|
|
70
|
+
4. Client with no cert saved yet: let in + log "no cert" (proposed) or block?
|
|
71
|
+
5. Remove or dev-limit the Compass `@togatech.com` → user 4273 shortcut (in this ticket or a new one)?
|
|
72
|
+
6. Rate's `entityIdentifier` holds its IdP URL, unlike the other rows — clean up when filling the new column?
|
|
73
|
+
7. Severity ~9/10 (10 if prod 4273 is admin) — who should be told before the fix ships?
|
|
74
|
+
|
|
75
|
+
## Exact next step
|
|
76
|
+
> Answer blocker questions 1-5 with the developer, then run the `cto` agent for a second opinion on the plan above before writing the dbchanges2 `Core/` SQL file.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
_Saved by /session-save on 2026-10-29_
|
package/package.json
CHANGED