toga-ai 1.0.549 → 1.0.550
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.
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
| [ClickUp Work Type Automation (Committed / Conditional / Stretch)](features/clickup-work-type-automation.md) | The ClickUp webhook handler (`_Worker_Clickup`) automatically maintains each task's **Work Type** custom field — `Committed`, `Conditional`, or `Stretch` — base | worker2/Worker/Clickup.php, worker2/Tests/Worker/ClickupWorkTypeTest.php |
|
|
18
18
|
| [Compass VIP Support Importer (worker2)](features/compass-vip-support-importer.md) | A worker2 action that ingests Compass's quarterly VIP spreadsheet and assigns each VIP user's support technician by setting `Users.c_supportedByUserId` in `Clie | worker2/Worker/Client/Compass/VipSupport.php |
|
|
19
19
|
| [Creating Worker Actions](features/creating-worker-actions.md) | How to add a new callable Worker action — a PHP class whose `public static` methods are invoked as background jobs (via webhook, cron, or `_Worker::runTask()`). | worker2/Worker/, worker2/Controller/Index.php, _underscore/Worker.php |
|
|
20
|
+
| [Cross-account AWS access for worker2 crons (_Component_Aws_Workloads)](features/cross-account-aws-access.md) | `_Component_Aws_Workloads` is the **standard, and only sanctioned, way any new worker2 cron obtains AWS access** — for any account, any region, any AWS SDK clie | worker2/Component/Aws/Workloads/Workloads.php, worker2/Config/production.ini, worker2/Worker/Infrastructure/CloudWatch.php |
|
|
20
21
|
| [Elite Freshservice Sync (worker2)](features/elite-freshservice-sync.md) | `_Worker_Elite` processes Freshservice webhook events and syncs them into TOGA 2. | worker2/Worker/Elite.php, worker2/Config/dev-kmaramreddy-laptop.ini |
|
|
21
22
|
| [Error Escalation Cron (Errors::Escalate → ClickUp / email)](features/error-escalation-cron.md) | `_Worker_Infrastructure_Errors::Escalate` (renamed from `SyncWithClickup`) is the sole owner of **escalation, de-escalation, ClickUp ticketing, reminders, busin | worker2/Worker/Infrastructure/Errors.php, worker2/Worker/Notification/Email.php, worker2/Worker/Notification/EmailTemplate.php, worker2/Worker/Client/True.php, worker2/Worker/Clickup/ErrorTask.php, worker2/Worker/Clickup.php, worker2/Controller/Index.php, worker2/Config/production.ini, _underscore/Model/Core/Logs/Issue.php, dbchanges2/Core/2026-07-30a - Error escalation cron job.sql, dbchanges2/Logs/2026-08-03a - Issue clickupPriority.sql, dbchanges2/Core/2026-08-04a - Error neglect digest cron job.sql |
|
|
22
23
|
| [Error-Issue Auto-Resolution & Reopen (frequency-decay lifecycle)](features/error-issue-auto-resolution.md) | The error system could escalate and de-escalate an Issue's *urgency* but had no concept of an Issue being **resolved**. | worker2/Worker/Infrastructure/Errors.php, worker2/Worker/Clickup/ErrorTask.php, _underscore/Model/Core/Logs/Issue.php, tools/mvc/errors/get.php, tools/mvc/errors/issue/get.php, dbchanges2/Logs/2026-08-05a - Issue status baseline and auto-resolution.sql |
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Cross-account AWS access for worker2 crons (_Component_Aws_Workloads)
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: worker2
|
|
5
|
+
project: Worker
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-08-10
|
|
10
|
+
owners: [jcardinal]
|
|
11
|
+
files:
|
|
12
|
+
- worker2/Component/Aws/Workloads/Workloads.php
|
|
13
|
+
- worker2/Config/production.ini
|
|
14
|
+
- worker2/Worker/Infrastructure/CloudWatch.php
|
|
15
|
+
related:
|
|
16
|
+
- ../../_underscore/features/component-model-namespace-registration.md
|
|
17
|
+
- ../../_underscore/features/config-group-access.md
|
|
18
|
+
- ../../_underscore/features/cloud-s3-helpers.md
|
|
19
|
+
- ./oneuptime-worker2-monitoring.md
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
|
|
24
|
+
`_Component_Aws_Workloads` is the **standard, and only sanctioned, way any new worker2 cron
|
|
25
|
+
obtains AWS access** — for any account, any region, any AWS SDK client. It replaces
|
|
26
|
+
hand-rolled `StsClient`/credential code and, more importantly, replaces the **legacy static
|
|
27
|
+
IAM-user access key** with a role-based model: the Elastic Beanstalk EC2 **instance role is
|
|
28
|
+
the worker's identity**, and it **assumes a per-account `WorkloadsRuntime` role** via STS to
|
|
29
|
+
reach each target account.
|
|
30
|
+
|
|
31
|
+
**Standard for all new AWS-touching worker2 code:** obtain credentials/clients through
|
|
32
|
+
`_Component_Aws_Workloads`. Do **not** instantiate `StsClient` by hand, and do **not** use
|
|
33
|
+
the legacy `[cloud]` static access key in new code paths (see
|
|
34
|
+
[Legacy static key](#legacy-static-key--being-retired)).
|
|
35
|
+
|
|
36
|
+
## Key files / entry points
|
|
37
|
+
|
|
38
|
+
- `worker2/Component/Aws/Workloads/Workloads.php` — `class _Component_Aws_Workloads`
|
|
39
|
+
(namespace `worker`, `extends \_Component`). Two static methods:
|
|
40
|
+
- `assumeCredentials(string $awsAccountId): array` → STS temporary credentials
|
|
41
|
+
`['key', 'secret', 'token']` for the `WorkloadsRuntime` role in the target account.
|
|
42
|
+
- `client(string $clientClass, string $awsAccountId, string $region): object` → a
|
|
43
|
+
ready-to-use SDK client of any `Aws\...\Client` class, already credentialed and
|
|
44
|
+
region-set.
|
|
45
|
+
- `worker2/Config/production.ini` — `[cloud]` group keys `workloads_role_name` and
|
|
46
|
+
`workloads_role_session`.
|
|
47
|
+
- `worker2/Worker/Infrastructure/CloudWatch.php` — first consumer (`ElasticBeanstalkHealth()`).
|
|
48
|
+
|
|
49
|
+
## How it works
|
|
50
|
+
|
|
51
|
+
1. The component builds an `StsClient` with **no explicit credentials**. The AWS SDK's
|
|
52
|
+
default provider chain therefore resolves to the **EB EC2 instance role**
|
|
53
|
+
(`ElasticBeanstalk-EC2-Instance-Profile`) — the worker's own identity. There are no
|
|
54
|
+
static keys in this path.
|
|
55
|
+
2. That instance role holds an inline policy `AssumeWorkloadsRuntime`
|
|
56
|
+
(`sts:AssumeRole` on `arn:aws:iam::*:role/WorkloadsRuntime`), so it can assume the
|
|
57
|
+
`WorkloadsRuntime` role in **any** account.
|
|
58
|
+
3. `assumeCredentials()` calls `AssumeRole` on
|
|
59
|
+
`arn:aws:iam::<awsAccountId>:role/WorkloadsRuntime` and returns the temporary creds.
|
|
60
|
+
4. `client()` uses those creds to construct the requested SDK client for the given region.
|
|
61
|
+
|
|
62
|
+
Role name and session are read from the `[cloud]` config group via `_Config::cloud()` with
|
|
63
|
+
`isGroupSet` / `isGroupPropertySet` guards, defaulting **in code** to role
|
|
64
|
+
`WorkloadsRuntime` / session `worker2-workloads` when the keys are absent — so non-prod
|
|
65
|
+
`.ini` files that lack the keys keep working (see
|
|
66
|
+
[_Config group access](../../_underscore/features/config-group-access.md)).
|
|
67
|
+
|
|
68
|
+
This is another concrete instance of the app-repo namespace pattern: `namespace worker` +
|
|
69
|
+
`extends \_Component`, referenced unqualified from `_Worker_*` classes via the autoloader
|
|
70
|
+
alias (see
|
|
71
|
+
[Component/Model namespace registration](../../_underscore/features/component-model-namespace-registration.md)).
|
|
72
|
+
|
|
73
|
+
## The WorkloadsRuntime role model (three accounts)
|
|
74
|
+
|
|
75
|
+
IAM is **global**, so **one `WorkloadsRuntime` role per account** covers all regions —
|
|
76
|
+
region is only a runtime argument to `client()`, never a reason for a second role.
|
|
77
|
+
|
|
78
|
+
- **654654170868** — production hub. Home region `us-east-1`; also used in `us-west-2` and
|
|
79
|
+
`eu-west-1`. worker2 runs here on Elastic Beanstalk; its instance profile role
|
|
80
|
+
`ElasticBeanstalk-EC2-Instance-Profile` is the caller identity.
|
|
81
|
+
- **502614707982** — legacy account, `us-west-2`.
|
|
82
|
+
- **975050298201** — non-production account, `us-east-1`.
|
|
83
|
+
|
|
84
|
+
Each `WorkloadsRuntime` role has broad service permissions (`elasticbeanstalk:*`, `ec2:*`,
|
|
85
|
+
`s3:*`, `sqs:*`, `cloudwatch:*`, `logs:*`, `ssm:*`, `autoscaling:*`,
|
|
86
|
+
`elasticloadbalancing:*`) and a **trust policy allowing the 868 instance role to assume
|
|
87
|
+
it**.
|
|
88
|
+
|
|
89
|
+
## First consumer — ElasticBeanstalkHealth (worked example)
|
|
90
|
+
|
|
91
|
+
`_Worker_Infrastructure_CloudWatch::ElasticBeanstalkHealth(awsAccountId,
|
|
92
|
+
elasticBeanstalkEnvironmentNames, oneuptimeUrl, region)` is a **parameterized cron** (args
|
|
93
|
+
spread from `Core.CronJobs.parameters` as named args) that reads each EB environment's
|
|
94
|
+
overall health through `_Component_Aws_Workloads::client(...)`, maps `HealthStatus`
|
|
95
|
+
`Degraded`/`Severe` → `alarm:"HIGH"`, and pushes a **non-fatal** OneUptime heartbeat
|
|
96
|
+
(`setLogging(false)`, `setThrowExceptionsOnFailure(false)` — the Compass push pattern; see
|
|
97
|
+
[OneUptime worker2 monitoring](./oneuptime-worker2-monitoring.md)).
|
|
98
|
+
|
|
99
|
+
It was refactored this session to use the new helper: the prior inline STS/credential code
|
|
100
|
+
and the `HEALTH_ASSUME_ROLE_NAME` / `HEALTH_ASSUME_ROLE_SESSION` constants were removed in
|
|
101
|
+
favor of `_Component_Aws_Workloads` + the `[cloud]` config keys. The prior
|
|
102
|
+
`CheckBeanstalks()` action was renamed `ElasticBeanstalkInstances()`
|
|
103
|
+
(dbchanges2 `Core/2026-08-10c` updates the CronJobs action name; `Core/2026-08-10d` seeds
|
|
104
|
+
the new parameterized `ElasticBeanstalkHealth` cron row, `isActive=0`).
|
|
105
|
+
|
|
106
|
+
## Legacy static key — being retired
|
|
107
|
+
|
|
108
|
+
The legacy `[cloud]` static access key is a **personal IAM user in account 502614707982**.
|
|
109
|
+
It is being retired for new code but is **still used by older code paths** — ZoomInfo,
|
|
110
|
+
VipSupport, and the `_Cloud` CLI path. **Retrofit of that existing code is deliberately
|
|
111
|
+
deferred** (developer decision, this session): document the new approach; do not migrate old
|
|
112
|
+
code yet. New code must not adopt the static key.
|
|
113
|
+
|
|
114
|
+
**Never record the access-key values in knowledge.** They exist in `production.ini`; that is
|
|
115
|
+
their only home.
|
|
116
|
+
|
|
117
|
+
## Gotchas / known issues
|
|
118
|
+
|
|
119
|
+
- Do not construct `StsClient` or pass explicit credentials by hand in new crons — the whole
|
|
120
|
+
point is that the instance role is the caller and the component owns the assume-role step.
|
|
121
|
+
- The instance-role-as-caller only works **on the EB tier**. Off-tier (e.g. a local CLI run)
|
|
122
|
+
the SDK default chain resolves differently; that is why the legacy `_Cloud` CLI path still
|
|
123
|
+
uses the static key for now.
|
|
124
|
+
- Config keys are optional by design (in-code defaults), so a missing `[cloud]`
|
|
125
|
+
`workloads_role_*` key silently uses `WorkloadsRuntime` / `worker2-workloads` — set them
|
|
126
|
+
explicitly in prod ini to override.
|
|
127
|
+
|
|
128
|
+
## Change history
|
|
129
|
+
- 2026-08-10 — Created. Added `_Component_Aws_Workloads` as the standard cross-account AWS
|
|
130
|
+
access helper (instance-role → per-account `WorkloadsRuntime` STS assume-role), documented
|
|
131
|
+
the three-account role model and `[cloud]` config keys, and recorded that the legacy static
|
|
132
|
+
IAM-user access key is retired for new code (existing ZoomInfo/VipSupport/_Cloud CLI paths
|
|
133
|
+
deferred). `ElasticBeanstalkHealth` is the first consumer. (jcardinal)
|
|
134
|
+
</content>
|
|
135
|
+
</invoke>
|
|
@@ -5,7 +5,7 @@ project: _Underscore
|
|
|
5
5
|
client: shared
|
|
6
6
|
type: standard
|
|
7
7
|
status: active
|
|
8
|
-
updated: 2026-08-
|
|
8
|
+
updated: 2026-08-10
|
|
9
9
|
owners: [jcardinal, mhammontree, dfranks]
|
|
10
10
|
files: []
|
|
11
11
|
related:
|
|
@@ -812,6 +812,25 @@ client sending a shallow depth.
|
|
|
812
812
|
|
|
813
813
|
* Ensure code is well-documented with comments and usage examples.
|
|
814
814
|
|
|
815
|
+
## AWS access (worker2)
|
|
816
|
+
|
|
817
|
+
### Obtain AWS credentials via _Component_Aws_Workloads — never static keys in new code
|
|
818
|
+
|
|
819
|
+
New worker2 code that touches AWS (any account, any region, any SDK client) must obtain
|
|
820
|
+
credentials/clients through `_Component_Aws_Workloads::assumeCredentials()` /
|
|
821
|
+
`::client()`. Do **not** construct `StsClient` or pass explicit credentials by hand, and do
|
|
822
|
+
**not** use the legacy `[cloud]` static IAM-user access key in new code paths.
|
|
823
|
+
|
|
824
|
+
The model: the Elastic Beanstalk EC2 instance role (`ElasticBeanstalk-EC2-Instance-Profile`,
|
|
825
|
+
account 654654170868) is the worker's identity and assumes a per-account `WorkloadsRuntime`
|
|
826
|
+
role via STS. IAM is global, so one `WorkloadsRuntime` role per account covers all regions.
|
|
827
|
+
|
|
828
|
+
Existing static-key paths (ZoomInfo, VipSupport, `_Cloud` CLI) are grandfathered — retrofit
|
|
829
|
+
is deferred, not sanctioned for new work. Never record access-key values anywhere but the ini.
|
|
830
|
+
|
|
831
|
+
See: 2.0/apps/worker2/features/cross-account-aws-access.md
|
|
832
|
+
|
|
815
833
|
## Change history
|
|
816
834
|
|
|
835
|
+
- 2026-08-10 — Added "AWS access (worker2)" section: new worker2 AWS code must use `_Component_Aws_Workloads` (instance-role → per-account `WorkloadsRuntime` STS assume-role); legacy static key grandfathered for existing paths only. (jcardinal)
|
|
817
836
|
- 2026-08-01 — Recorded the Logs-cluster singular table-naming exception to the otherwise-plural table convention. (jcardinal)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -19,7 +19,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
19
19
|
## 2.0 framework
|
|
20
20
|
|
|
21
21
|
- **_underscore** (_Underscore) _(framework core)_ — 50 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
22
|
-
- **worker2** (Worker) —
|
|
22
|
+
- **worker2** (Worker) — 46 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
23
23
|
- **api2** (API) — 22 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
24
24
|
- **dbchanges2** (Database Changes) _(framework core)_ — 8 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
25
25
|
- **toga2-supply** (TOGa Supply) — 5 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
|
package/package.json
CHANGED