toga-ai 1.0.206 → 1.0.207
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/1.0/apps/library/architecture.md +10 -0
- package/knowledge/1.0/apps/tools/INDEX.md +8 -0
- package/knowledge/1.0/apps/tools/architecture.md +81 -0
- package/knowledge/1.0/apps/tools/features/developer-tools.md +37 -0
- package/knowledge/1.0/apps/tools/features/persona-gated-navigation.md +44 -0
- package/knowledge/1.0/apps/tools/features/saml-sso-auth.md +76 -0
- package/knowledge/INDEX.md +2 -1
- package/knowledge/clients/true/profile.md +4 -0
- package/knowledge/registry.json +9 -0
- package/package.json +1 -1
|
@@ -103,3 +103,13 @@ packages: `phpoffice/phpspreadsheet ^1.6`, `smalot/pdfparser ^0.14.0`.
|
|
|
103
103
|
- **Timezone** is always `America/Chicago` (set in `_.php`).
|
|
104
104
|
- **`__APPROOT__`** is resolved by locating an ancestor folder named `_`; each app must
|
|
105
105
|
have that `_` folder at its root.
|
|
106
|
+
|
|
107
|
+
## App_String cross-framework crypto (`encryptWithKey` / `decryptWithKey`)
|
|
108
|
+
|
|
109
|
+
`App_String::encryptWithKey($data, $key)` and `decryptWithKey($data, $key)` (public static) do
|
|
110
|
+
**AES-256-CBC**: random IV via `random_bytes`, returning `base64(iv . ciphertext)` with openssl
|
|
111
|
+
flag `0`. They are **deliberately byte-for-byte interoperable** with the 2.0
|
|
112
|
+
`_String::encryptWithKey` / `decryptWithKey`, so a SAML handoff token encrypted by the 2.0
|
|
113
|
+
gateway decrypts in any 1.0 app (round-trip verified). Net-new methods — no existing method
|
|
114
|
+
changed, no behavior change for existing apps. First consumer: the Tools app's `App_Auth`
|
|
115
|
+
(`1.0/apps/tools/features/saml-sso-auth.md`).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# tools (Tools) — 1.0 knowledge
|
|
2
|
+
|
|
3
|
+
| Doc | Summary | Files |
|
|
4
|
+
|-----|---------|-------|
|
|
5
|
+
| [Tools (1.0 Internal-Tools App) Architecture](architecture.md) | **Tools** is a standalone 1.0 (`App_`) application that houses many small internal tools behind simple interfaces, gated by Client_True staff persona. | tools/index.php, tools/_/app/framework.php, tools/_/app/frameworkindex.php, tools/_/app/auth.php, tools/_/app/nav.php, tools/common/header.php, tools/common/footer.php, tools/mvc/get.php, tools/mvc/_TEMPLATE/get.php, tools/docs/ADDING_A_TOOL.md |
|
|
6
|
+
| [Tools — Developers Folder (UUID & Password Generators)](features/developer-tools.md) | The first two tools shipped in the Tools app, both under the **Developers** folder and gated to personas **Development Team** / **TOGa Technology**. | tools/mvc/developers/uuid/get.php, tools/mvc/developers/password/get.php |
|
|
7
|
+
| [Tools Persona-Gated Navigation (App_Nav)](features/persona-gated-navigation.md) | `App_Nav` is the Tools app's two-level, **persona-gated** navigation. | tools/_/app/nav.php |
|
|
8
|
+
| [Tools SAML SSO Consumer & Persona-Gated Auth (App_Auth)](features/saml-sso-auth.md) | `App_Auth` is the Tools app's authentication layer: it consumes the SAML gateway `?saml=` handoff (see the 2.0 SAML downstream integration contract), establishe | tools/_/app/auth.php, tools/mvc/sso/get.php, tools/mvc/login/get.php, tools/mvc/login/post.php, tools/mvc/logout/get.php |
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tools (1.0 Internal-Tools App) Architecture
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: tools
|
|
5
|
+
project: Tools
|
|
6
|
+
client: shared
|
|
7
|
+
type: architecture
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-25
|
|
10
|
+
owners: [jcardinal]
|
|
11
|
+
files:
|
|
12
|
+
- tools/index.php
|
|
13
|
+
- tools/_/app/framework.php
|
|
14
|
+
- tools/_/app/frameworkindex.php
|
|
15
|
+
- tools/_/app/auth.php
|
|
16
|
+
- tools/_/app/nav.php
|
|
17
|
+
- tools/common/header.php
|
|
18
|
+
- tools/common/footer.php
|
|
19
|
+
- tools/mvc/get.php
|
|
20
|
+
- tools/mvc/_TEMPLATE/get.php
|
|
21
|
+
- tools/docs/ADDING_A_TOOL.md
|
|
22
|
+
related:
|
|
23
|
+
- ./features/saml-sso-auth.md
|
|
24
|
+
- ./features/persona-gated-navigation.md
|
|
25
|
+
- ./features/developer-tools.md
|
|
26
|
+
- ../library/architecture.md
|
|
27
|
+
- ../library/features/mvc-page-pattern-and-app-skeleton.md
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Summary
|
|
31
|
+
|
|
32
|
+
**Tools** is a standalone 1.0 (`App_`) application that houses many small internal tools behind
|
|
33
|
+
simple interfaces, gated by Client_True staff persona. It is modeled on `togaview` and depends on
|
|
34
|
+
the `library` core. Auth comes via the SAML gateway `?saml=` handoff; the app owns its own
|
|
35
|
+
session and reads `Client_True` **read-only**. Adding a tool = create `mvc/<route>/get.php`
|
|
36
|
+
(copy `mvc/_TEMPLATE`) + add one `App_Nav::definition()` entry + `App_Auth::requireAuth([...])`.
|
|
37
|
+
|
|
38
|
+
**Critical rules:** Do NOT use bare `<header>` elements in this app — they inherit the legacy
|
|
39
|
+
dashboard stylesheet's `header{position:fixed;width:100vw}` rule and cause horizontal scroll
|
|
40
|
+
(the top header bar was removed for exactly this reason). A nav action's `route` maps **1:1** to
|
|
41
|
+
`mvc/<route>/get.php`. Auth fails **closed** and never auto-creates users; the dev bypass is
|
|
42
|
+
double-gated (`[internal] dev_mode` AND `App_Registry::inDevMode()`). `config.*.ini`
|
|
43
|
+
(incl. `config.prod.ini`) is committed with plaintext production secrets — a known, team-accepted
|
|
44
|
+
risk (see Known issues); never add more secrets and treat these as compromised if leaked.
|
|
45
|
+
|
|
46
|
+
## Boot & structure
|
|
47
|
+
|
|
48
|
+
Standard 3-line `index.php`: `require '_.php'; App_Framework_Tools::initialize();
|
|
49
|
+
App_Framework_Tools::renderIndex();`. App-specific framework subclasses
|
|
50
|
+
`App_Framework_Tools` / `App_FrameworkIndex_Tools` live in `_/app/`. The 1.0 folder-based MVC
|
|
51
|
+
page pattern is unchanged from the library skeleton (see the library feature doc).
|
|
52
|
+
|
|
53
|
+
`App_Framework_Tools::initialize()` sets the session cookie HttpOnly + SameSite=Lax before
|
|
54
|
+
calling the parent initialize.
|
|
55
|
+
|
|
56
|
+
## Layout (single-style app)
|
|
57
|
+
|
|
58
|
+
No per-host `stylePath` subfolder — one `assets/css/style.css`. Uses TOGA Technology logos in
|
|
59
|
+
`assets/img` (`toga-brandmark-white.png` in the dark sidebar; `toga-horizontal-colored.png` on
|
|
60
|
+
login/welcome). A fixed left two-column shell: dark left sidebar (`.app-nav`) with brand at top,
|
|
61
|
+
persona-filtered nav in the middle, pinned footer with the user's name + a ghost "Log out"
|
|
62
|
+
button; content area on the right. **No top header bar** (see Critical rules).
|
|
63
|
+
|
|
64
|
+
## Home route
|
|
65
|
+
|
|
66
|
+
`/` (`mvc/get.php`) renders a persona-filtered dashboard of available tools (tiles grouped by
|
|
67
|
+
folder) when logged in, via `App_Nav::visibleGroups()`, or a welcome/sign-in card when not.
|
|
68
|
+
|
|
69
|
+
## Adding a tool
|
|
70
|
+
|
|
71
|
+
Create `mvc/<folder>/<tool>/get.php` (copy `mvc/_TEMPLATE/get.php`), add one entry to
|
|
72
|
+
`App_Nav::definition()`, and put `App_Auth::requireAuth([...personas])` at the top. Documented in
|
|
73
|
+
`docs/ADDING_A_TOOL.md`. See the App_Nav and App_Auth feature docs.
|
|
74
|
+
|
|
75
|
+
## Known issues / security
|
|
76
|
+
|
|
77
|
+
- **Plaintext secrets committed to git.** `config.*.ini` (incl. `config.prod.ini`) contains
|
|
78
|
+
plaintext production secrets (RDS master password, SMTP, Payeezy, NetSuite). The team has
|
|
79
|
+
**accepted this for now** (developer decision, 2026-06-25). Future remediation: git-ignore the
|
|
80
|
+
config files and rotate all exposed credentials. (Location only — no values recorded here.)
|
|
81
|
+
- **SSO initiation + replay defense are open items** — see `features/saml-sso-auth.md`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tools — Developers Folder (UUID & Password Generators)
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: tools
|
|
5
|
+
project: Tools
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-25
|
|
10
|
+
owners: [jcardinal]
|
|
11
|
+
files:
|
|
12
|
+
- tools/mvc/developers/uuid/get.php
|
|
13
|
+
- tools/mvc/developers/password/get.php
|
|
14
|
+
related:
|
|
15
|
+
- ../architecture.md
|
|
16
|
+
- ./persona-gated-navigation.md
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Summary
|
|
20
|
+
|
|
21
|
+
The first two tools shipped in the Tools app, both under the **Developers** folder and gated to
|
|
22
|
+
personas **Development Team** / **TOGa Technology**. They are the reference example of the
|
|
23
|
+
"one small tool = one `mvc/<route>/get.php`" pattern.
|
|
24
|
+
|
|
25
|
+
## How it works
|
|
26
|
+
|
|
27
|
+
### Generate UUID (`mvc/developers/uuid/get.php`)
|
|
28
|
+
- Server generates an RFC 4122 **v4** UUID via `random_bytes(16)` with version/variant bits set.
|
|
29
|
+
- UI is click-to-copy, then instant **client-side** regenerate using `crypto.getRandomValues`.
|
|
30
|
+
|
|
31
|
+
### Generate Password (`mvc/developers/password/get.php`)
|
|
32
|
+
- Reproduces the standalone `test/team/generate_password.php` script.
|
|
33
|
+
- `App_String::generateSupportCode(8)` produces the password; `App_String::passwordHash()`
|
|
34
|
+
produces the bcrypt hash. The page shows **both** the password and the hash, each copyable.
|
|
35
|
+
|
|
36
|
+
## Change history
|
|
37
|
+
- 2026-06-25 — Built the first two Developers tools: RFC 4122 v4 UUID generator and a password+bcrypt-hash generator (ported from test/team/generate_password.php), both gated to Development Team / TOGa Technology personas (jcardinal)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tools Persona-Gated Navigation (App_Nav)
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: tools
|
|
5
|
+
project: Tools
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-25
|
|
10
|
+
owners: [jcardinal]
|
|
11
|
+
files:
|
|
12
|
+
- tools/_/app/nav.php
|
|
13
|
+
related:
|
|
14
|
+
- ../architecture.md
|
|
15
|
+
- ./saml-sso-auth.md
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Summary
|
|
19
|
+
|
|
20
|
+
`App_Nav` is the Tools app's two-level, **persona-gated** navigation. The structure is a single
|
|
21
|
+
**hard-coded `definition()` array** (NOT in the DB), so developers/Claude edit it directly. It
|
|
22
|
+
drives both the left-rail nav and the home dashboard, and is the single source of truth for which
|
|
23
|
+
personas may reach a given route.
|
|
24
|
+
|
|
25
|
+
## How it works
|
|
26
|
+
|
|
27
|
+
### Structure
|
|
28
|
+
- Two levels: **folders** (grouping) → **actions** (each loads a page).
|
|
29
|
+
- Each folder and each action carries a `personas` list. An item is visible iff
|
|
30
|
+
`App_Auth::hasAnyPersona()` matches — folder gate plus an optional per-action gate.
|
|
31
|
+
|
|
32
|
+
### Render surfaces
|
|
33
|
+
- `render()` — emits the filtered left-rail nav with active-route highlighting.
|
|
34
|
+
- `visibleGroups()` — returns the filtered structure as data for the home dashboard tiles.
|
|
35
|
+
- `personasForRoute()` — returns the union of folder+action personas so a page can self-guard
|
|
36
|
+
with `App_Auth::requireAuth(...)` using the same data the nav used.
|
|
37
|
+
|
|
38
|
+
### Route convention
|
|
39
|
+
An action's `route` (e.g. `/developers/uuid`) maps **1:1** to `mvc/<route>/get.php`. Adding a
|
|
40
|
+
tool means creating that file and adding one entry to `definition()` — see
|
|
41
|
+
`docs/ADDING_A_TOOL.md` and the architecture doc.
|
|
42
|
+
|
|
43
|
+
## Change history
|
|
44
|
+
- 2026-06-25 — Built App_Nav: hard-coded two-level persona-gated navigation; render() for the left rail, visibleGroups() for the dashboard, personasForRoute() for page self-guarding; route maps 1:1 to mvc/<route>/get.php (jcardinal)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tools SAML SSO Consumer & Persona-Gated Auth (App_Auth)
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: tools
|
|
5
|
+
project: Tools
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-25
|
|
10
|
+
owners: [jcardinal]
|
|
11
|
+
files:
|
|
12
|
+
- tools/_/app/auth.php
|
|
13
|
+
- tools/mvc/sso/get.php
|
|
14
|
+
- tools/mvc/login/get.php
|
|
15
|
+
- tools/mvc/login/post.php
|
|
16
|
+
- tools/mvc/logout/get.php
|
|
17
|
+
related:
|
|
18
|
+
- ../architecture.md
|
|
19
|
+
- ../../../2.0/apps/saml/features/downstream-integration-contract.md
|
|
20
|
+
- ../../../clients/true/features/users-personas-data-model.md
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
|
|
25
|
+
`App_Auth` is the Tools app's authentication layer: it consumes the SAML gateway `?saml=`
|
|
26
|
+
handoff (see the 2.0 SAML downstream integration contract), establishes its own session, and
|
|
27
|
+
gates every page by **Client_True persona**. The gateway holds no session — session ownership
|
|
28
|
+
is entirely this app's. Auth fails **closed** to a self-contained 401 page; users are **never**
|
|
29
|
+
auto-created.
|
|
30
|
+
|
|
31
|
+
## How it works
|
|
32
|
+
|
|
33
|
+
### Consuming the `?saml=` handoff (`mvc/sso/get.php` → `App_Auth`)
|
|
34
|
+
1. Length-guard `$_GET['saml']`, then base64-decode → `json_decode` → read `payload.client`
|
|
35
|
+
and `payload.user`.
|
|
36
|
+
2. Decrypt each with `App_String::decryptWithKey()` using config `[saml] api_secret_access_token`,
|
|
37
|
+
with a **dual-key retry** against `api_secret_access_token_previous` (supports gateway key
|
|
38
|
+
rotation). This interoperates byte-for-byte with the 2.0 `_String::encryptWithKey()` that
|
|
39
|
+
produced the token (see the library `App_String` crypto methods).
|
|
40
|
+
3. Validate the decrypted **client uuid == configured `true_client_uuid`** via `hash_equals`,
|
|
41
|
+
and that both decrypted values match a UUID regex.
|
|
42
|
+
4. Load the active Client_True user: `WHERE uuid = ? AND isActive = 1`. No match → fail closed.
|
|
43
|
+
|
|
44
|
+
### Session establishment (`establishSession()`)
|
|
45
|
+
- Calls `session_regenerate_id(true)`, then caches the user and **persona names** in `$_SESSION`.
|
|
46
|
+
- Persona lookup (read-only `db_true`):
|
|
47
|
+
`SELECT p.name FROM Users u JOIN Users_Personas up ON up.userId=u.id JOIN Personas p ON p.id=up.personaId WHERE u.uuid = <escaped>`.
|
|
48
|
+
- The session cookie is set **HttpOnly + SameSite=Lax** in `App_Framework_Tools::initialize()`
|
|
49
|
+
before the parent initialize runs.
|
|
50
|
+
|
|
51
|
+
### Page guarding
|
|
52
|
+
- `requireAuth([personas])` at the top of each page; `hasAnyPersona()` is `array_intersect`
|
|
53
|
+
against the cached session personas. App_Nav uses the same cached data to filter the nav.
|
|
54
|
+
|
|
55
|
+
### Dev bypass (double-gated, fails closed in prod)
|
|
56
|
+
`mvc/login/post.php` permits **email-only** login **only** when config `[internal] dev_mode`
|
|
57
|
+
is truthy **and** `App_Registry::inDevMode()` — both must hold. When used it writes a `SECURITY`
|
|
58
|
+
line to `error_log`.
|
|
59
|
+
|
|
60
|
+
## Gotchas / known issues
|
|
61
|
+
|
|
62
|
+
- **SSO initiation is not implemented in this 1.0 app.** Building the signed AuthnRequest lives
|
|
63
|
+
in 2.0 `_underscore` (`singleSignOnServiceUrl()`); login here points at a configurable
|
|
64
|
+
`[saml] initiation_url` **placeholder**. Open item: needs a gateway initiation entry point or
|
|
65
|
+
a ported builder.
|
|
66
|
+
- **No app-side replay defense.** The handoff token carries no nonce/timestamp the app verifies.
|
|
67
|
+
Recommend the gateway embed `iat` + `jti`.
|
|
68
|
+
|
|
69
|
+
## Config keys
|
|
70
|
+
|
|
71
|
+
`[database_true]` (read-only Client_True); `[saml]` `api_secret_access_token` /
|
|
72
|
+
`api_secret_access_token_previous`, `initiation_url`, `client_authentication_uuid`,
|
|
73
|
+
`domain_uuid`, `true_client_uuid`; `[internal]` `dev_mode`.
|
|
74
|
+
|
|
75
|
+
## Change history
|
|
76
|
+
- 2026-06-25 — Built App_Auth: SAML `?saml=` handoff consumer with dual-key decrypt, hash_equals client-uuid check, fail-closed 401, persona-cached session (HttpOnly+SameSite=Lax), and a double-gated dev bypass. Initiation + replay defense left as open items (jcardinal)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -12,6 +12,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
12
12
|
- **walmarttechservices** (Walmart Tech Services) — 1 doc(s) → [1.0/apps/walmarttechservices/INDEX.md](1.0/apps/walmarttechservices/INDEX.md)
|
|
13
13
|
- **test** (Test) — 11 doc(s) → [1.0/apps/test/INDEX.md](1.0/apps/test/INDEX.md)
|
|
14
14
|
- **toga** (TOGa) — 2 doc(s) → [1.0/apps/toga/INDEX.md](1.0/apps/toga/INDEX.md)
|
|
15
|
+
- **tools** (Tools) — 4 doc(s) → [1.0/apps/tools/INDEX.md](1.0/apps/tools/INDEX.md)
|
|
15
16
|
|
|
16
17
|
## 2.0 framework
|
|
17
18
|
|
|
@@ -27,7 +28,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
27
28
|
- **voice-to-voice** (TOGa Voice) — 4 doc(s) → [2.0/apps/voice-to-voice/INDEX.md](2.0/apps/voice-to-voice/INDEX.md)
|
|
28
29
|
- **ai-bdr** (AI-BDR) — 4 doc(s) → [2.0/apps/ai-bdr/INDEX.md](2.0/apps/ai-bdr/INDEX.md)
|
|
29
30
|
- **toga2-commerce** (TOGa Commerce) — 6 doc(s) → [2.0/apps/toga2-commerce/INDEX.md](2.0/apps/toga2-commerce/INDEX.md)
|
|
30
|
-
- **toga25-supply** (TOGa 2.5 Supply) —
|
|
31
|
+
- **toga25-supply** (TOGa 2.5 Supply) — 7 doc(s) → [2.0/apps/toga25-supply/INDEX.md](2.0/apps/toga25-supply/INDEX.md)
|
|
31
32
|
- **toga-blox** (TOGa Blox) — 7 doc(s) → [2.0/apps/toga-blox/INDEX.md](2.0/apps/toga-blox/INDEX.md)
|
|
32
33
|
|
|
33
34
|
## standalone framework
|
|
@@ -3,6 +3,7 @@ title: "TOGA Technology"
|
|
|
3
3
|
framework: "2.0"
|
|
4
4
|
apps:
|
|
5
5
|
- _underscore
|
|
6
|
+
- tools
|
|
6
7
|
project: _Underscore
|
|
7
8
|
client: true
|
|
8
9
|
type: profile
|
|
@@ -24,3 +25,6 @@ by staff role (e.g. the planned Toolbox app) reads its `Users` / `Personas` mode
|
|
|
24
25
|
- **Client DB:** `Client_True`
|
|
25
26
|
- **Client identifier:** `True`
|
|
26
27
|
- **SSO mapper:** `_Model_True_ClientAuthentication` (base; matches by email from NameID)
|
|
28
|
+
|
|
29
|
+
The new **Tools** app (1.0; repo `tools`) reads the `Client_True` DB **read-only** to gate its
|
|
30
|
+
internal tooling by staff persona (see `1.0/apps/tools/`).
|
package/knowledge/registry.json
CHANGED
package/package.json
CHANGED