razzou-harness 0.4.1 → 0.4.2
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/CHANGELOG.md +28 -0
- package/README.md +13 -8
- package/dist/design/schemas.js +2 -2
- package/dist/sandbox/aws-services.js +428 -0
- package/dist/sandbox/policy.js +36 -13
- package/dist/setup/doctor.js +2 -2
- package/dist/setup/setup.js +4 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,34 @@
|
|
|
3
3
|
The notable changes in each release of razzou-harness. Before 1.0, a new minor version
|
|
4
4
|
may change how a project is set up, and its notes say how.
|
|
5
5
|
|
|
6
|
+
## 0.4.2 (2026-11-08)
|
|
7
|
+
|
|
8
|
+
**Upgrading from 0.4.1:** upgrade OpenShell to 0.1.7 first, from its Debian package
|
|
9
|
+
(`sudo dpkg -i openshell_0.1.7-1_amd64.deb`); the gateway keeps its providers and
|
|
10
|
+
profiles. Then install the new version, and rebuild the agents' image with `harness
|
|
11
|
+
doctor --build-images`: its tag follows the harness's version. A project's AWS services
|
|
12
|
+
stay as its `harness/config.json` lists them; for every one, set `"services": ["all"]`
|
|
13
|
+
under `aws`.
|
|
14
|
+
|
|
15
|
+
- **OpenShell 0.1.7.** The harness is pinned to it, and tested with it: the probe passes
|
|
16
|
+
with every bundle and every AWS service, and the Architect's terminal and the shell
|
|
17
|
+
in a sandbox work. The doctor's and setup's fix for a stopped gateway now starts its
|
|
18
|
+
systemd user service: OpenShell's CLI has no command for it.
|
|
19
|
+
- **Every AWS service by default.** `"all"` in `aws.services` is every service the AWS
|
|
20
|
+
SDK knows, about 420 endpoints in a region with the global ones, each signed with the
|
|
21
|
+
view role under its own signing name, as OpenShell requires. It is the default, and
|
|
22
|
+
`harness setup` no longer asks which services the project uses: the view role alone
|
|
23
|
+
decides what agents read. The table comes from the AWS SDK's own data
|
|
24
|
+
(`scripts/aws-services.ts` writes it).
|
|
25
|
+
- **AWS reads with `GET` work.** OpenShell's automatic `sigv4` mode signs a request
|
|
26
|
+
with neither a body nor `x-amz-content-sha256` as `UNSIGNED-PAYLOAD`, which only S3
|
|
27
|
+
accepts ([NVIDIA/OpenShell#5375](https://github.com/NVIDIA/OpenShell/issues/5375)):
|
|
28
|
+
every service that reads with `GET`, such as Lambda, API Gateway, EKS, Route 53,
|
|
29
|
+
CloudFront and Bedrock, answered `SignatureDoesNotMatch` in the sandboxes, and a
|
|
30
|
+
`terraform plan` there failed on their resources. Every AWS endpoint but S3's is now
|
|
31
|
+
signed with `sigv4:body`, the hash of the request's body, empty for a `GET`: the AWS
|
|
32
|
+
CLI's calls to those services and a `terraform plan` reading them work.
|
|
33
|
+
|
|
6
34
|
## 0.4.1 (2026-11-08)
|
|
7
35
|
|
|
8
36
|
**Upgrading a project from 0.4.0:** install the new version, then rebuild the agents'
|
package/README.md
CHANGED
|
@@ -106,7 +106,7 @@ without pull requests.
|
|
|
106
106
|
|
|
107
107
|
- Linux, Node 24 or later, git, Docker, and `gh` logged in as an admin of your
|
|
108
108
|
project's repository.
|
|
109
|
-
- OpenShell 0.1.
|
|
109
|
+
- OpenShell 0.1.7 with a running gateway. The harness is tested with this version only,
|
|
110
110
|
and `harness doctor` refuses others.
|
|
111
111
|
- Claude Code on this machine, with a Claude subscription: its binary goes into the
|
|
112
112
|
sandbox image, and `claude setup-token` gives the agents' token. Access with an API
|
|
@@ -433,7 +433,7 @@ through an `Arch:` pull request, or a commit of your own on `main`.
|
|
|
433
433
|
|
|
434
434
|
```json
|
|
435
435
|
{
|
|
436
|
-
"harnessVersion": "0.4.
|
|
436
|
+
"harnessVersion": "0.4.2",
|
|
437
437
|
"project": { "name": "shop", "repo": "<org>/shop", "bot": "<org>-harness[bot]" },
|
|
438
438
|
"roles": {
|
|
439
439
|
"architect": { "model": "claude-opus-5-5", "effort": "max" },
|
|
@@ -558,13 +558,18 @@ and Terraform applies only in CI, after you merge.
|
|
|
558
558
|
1. In `harness/config.json`, add `aws` and `terraform`:
|
|
559
559
|
|
|
560
560
|
```json
|
|
561
|
-
"aws": { "region": "us-east-1", "provider": "aws-view-<org>-shop", "services": ["
|
|
561
|
+
"aws": { "region": "us-east-1", "provider": "aws-view-<org>-shop", "services": ["all"] },
|
|
562
562
|
"terraform": { "dir": "iac", "backendConfig": "backend-configs/staging.hcl", "varFile": "env/staging.tfvars" }
|
|
563
563
|
```
|
|
564
564
|
|
|
565
|
-
`services` lists the AWS services
|
|
566
|
-
|
|
567
|
-
|
|
565
|
+
`services` lists the AWS services whose endpoints the sandboxes reach, signed with
|
|
566
|
+
the view role. `all`, the default, is every service the AWS SDK knows, so the view
|
|
567
|
+
role alone decides what agents read; a list of names narrows it. Every service but S3
|
|
568
|
+
is signed with the hash of the request's body, empty for a `GET`: OpenShell's
|
|
569
|
+
automatic mode signs a bodiless `GET` in a way only S3 accepts
|
|
570
|
+
([NVIDIA/OpenShell#5375](https://github.com/NVIDIA/OpenShell/issues/5375)). Keep the `terraform` paths
|
|
571
|
+
as they are: the CI workflow uses the same ones. `harness github-setup` then requires
|
|
572
|
+
`tf-plan` as well.
|
|
568
573
|
2. Set the repository variables the workflow reads: `AWS_REGION_STAGING`,
|
|
569
574
|
`AWS_ROLE_PLAN_ARN_STAGING` and `AWS_ROLE_APPLY_ARN_STAGING`.
|
|
570
575
|
3. `harness doctor` creates the OpenShell AWS provider: it asks for the view role's ARN,
|
|
@@ -643,8 +648,8 @@ To report a vulnerability, see `SECURITY.md` in the source repository.
|
|
|
643
648
|
|---|---|
|
|
644
649
|
| `Docker: … permission denied` | Add yourself to the `docker` group, then log in again |
|
|
645
650
|
| `Tailscale: an exit node is active`, or `container network` fails | An exit node can cut the containers' network: turn it off |
|
|
646
|
-
| `OpenShell: … pinned to 0.1.
|
|
647
|
-
| `OpenShell gateway` fails | `openshell gateway
|
|
651
|
+
| `OpenShell: … pinned to 0.1.7` | Install OpenShell 0.1.7, from its Debian package |
|
|
652
|
+
| `OpenShell gateway` fails | `systemctl --user start openshell-gateway`: the gateway is a systemd user service |
|
|
648
653
|
| `image: … has Claude Code X, this machine Y` | `harness doctor --build-images`, after each Claude Code update |
|
|
649
654
|
| `terminals: node-pty is missing` | Install `python3`, `make` and `g++`, then reinstall with `--allow-scripts=node-pty`. `harness attach` works meanwhile. |
|
|
650
655
|
| `Claude provider: … is missing` | `claude setup-token`, then `harness doctor` in a terminal: it asks for the token |
|
package/dist/design/schemas.js
CHANGED
|
@@ -165,8 +165,8 @@ export const ConfigSchema = z.object({
|
|
|
165
165
|
region: z.string().regex(/^[a-z]{2}(-[a-z]+)+-\d$/, 'an AWS region, like us-east-1'),
|
|
166
166
|
/** The OpenShell provider holding the view role, like "aws-view-shop". */
|
|
167
167
|
provider: z.string().min(1),
|
|
168
|
-
/** The services
|
|
169
|
-
services: z.array(z.string().regex(/^[a-z0-9-]+$/)).default(['
|
|
168
|
+
/** The services whose endpoints are reachable, and signed; `all`, the default, is every one, so the view role alone decides. */
|
|
169
|
+
services: z.array(z.string().regex(/^[a-z0-9-]+$/)).default(['all']),
|
|
170
170
|
})
|
|
171
171
|
.optional(),
|
|
172
172
|
/** Where the project's Terraform lives, and how a plan is made against the real state (§12.4). */
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
// Generated by scripts/aws-services.ts from botocore's data (AWS CLI 2.36.48): don't edit it by hand.
|
|
2
|
+
/** Every regional AWS service: its endpoint prefix, its signing name, and its host when not `{service}.{region}.{dnsSuffix}`. */
|
|
3
|
+
export const REGIONAL_SERVICES = [
|
|
4
|
+
['a2i-runtime.sagemaker', 'sagemaker'],
|
|
5
|
+
['access-analyzer', 'access-analyzer'],
|
|
6
|
+
['account-access', 'account-access'],
|
|
7
|
+
['acm', 'acm'],
|
|
8
|
+
['acm-pca', 'acm-pca'],
|
|
9
|
+
['aco-automation', 'aco-automation'],
|
|
10
|
+
['admin.wickr', 'wickr'],
|
|
11
|
+
['agent-registry', 'agent-registry'],
|
|
12
|
+
['agent-registry-control', 'agent-registry'],
|
|
13
|
+
['agenttoolkit', 'execute-api'],
|
|
14
|
+
['agreement-marketplace', 'aws-marketplace'],
|
|
15
|
+
['aidevops', 'aidevops'],
|
|
16
|
+
['aiops', 'aiops'],
|
|
17
|
+
['airflow', 'airflow'],
|
|
18
|
+
['airflow-serverless', 'airflow-serverless'],
|
|
19
|
+
['amplify', 'amplify'],
|
|
20
|
+
['amplifybackend', 'amplifybackend'],
|
|
21
|
+
['amplifyuibuilder', 'amplifyuibuilder'],
|
|
22
|
+
['aoss', 'aoss'],
|
|
23
|
+
['api.detective', 'detective'],
|
|
24
|
+
['api.ecr', 'ecr'],
|
|
25
|
+
['api.ecr-public', 'ecr-public'],
|
|
26
|
+
['api.iotdeviceadvisor', 'iotdeviceadvisor'],
|
|
27
|
+
['api.iotmanagedintegrations', 'iotmanagedintegrations'],
|
|
28
|
+
['api.iotwireless', 'iotwireless'],
|
|
29
|
+
['api.mediatailor', 'mediatailor'],
|
|
30
|
+
['api.pricing', 'pricing'],
|
|
31
|
+
['api.sagemaker', 'sagemaker'],
|
|
32
|
+
['api.tunneling.iot', 'IoTSecuredTunneling'],
|
|
33
|
+
['apigateway', 'apigateway'],
|
|
34
|
+
['app-integrations', 'app-integrations'],
|
|
35
|
+
['appconfig', 'appconfig'],
|
|
36
|
+
['appconfigdata', 'appconfig'],
|
|
37
|
+
['appfabric', 'appfabric'],
|
|
38
|
+
['appflow', 'appflow'],
|
|
39
|
+
['application-autoscaling', 'application-autoscaling'],
|
|
40
|
+
['application-cost-profiler', 'application-cost-profiler'],
|
|
41
|
+
['application-signals', 'application-signals'],
|
|
42
|
+
['applicationinsights', 'applicationinsights'],
|
|
43
|
+
['appmesh', 'appmesh'],
|
|
44
|
+
['apprunner', 'apprunner'],
|
|
45
|
+
['appstream2', 'appstream'],
|
|
46
|
+
['appsync', 'appsync'],
|
|
47
|
+
['aps', 'aps'],
|
|
48
|
+
['arc-region-switch', 'arc-region-switch'],
|
|
49
|
+
['arc-zonal-shift', 'arc-zonal-shift'],
|
|
50
|
+
['artifact', 'artifact'],
|
|
51
|
+
['athena', 'athena'],
|
|
52
|
+
['auditmanager', 'auditmanager'],
|
|
53
|
+
['autoscaling', 'autoscaling'],
|
|
54
|
+
['autoscaling-plans', 'autoscaling-plans'],
|
|
55
|
+
['b2bi', 'b2bi'],
|
|
56
|
+
['backup', 'backup'],
|
|
57
|
+
['backup-gateway', 'backup-gateway'],
|
|
58
|
+
['backup-search', 'backup-search'],
|
|
59
|
+
['batch', 'batch'],
|
|
60
|
+
['bcm-dashboards', 'bcm-dashboards'],
|
|
61
|
+
['bcm-data-exports', 'bcm-data-exports'],
|
|
62
|
+
['bcm-pricing-calculator', 'bcm-pricing-calculator'],
|
|
63
|
+
['bcm-recommended-actions', 'bcm-recommended-actions'],
|
|
64
|
+
['bedrock', 'bedrock'],
|
|
65
|
+
['bedrock-agent', 'bedrock'],
|
|
66
|
+
['bedrock-agent-runtime', 'bedrock'],
|
|
67
|
+
['bedrock-agentcore', 'bedrock-agentcore'],
|
|
68
|
+
['bedrock-agentcore-control', 'bedrock-agentcore'],
|
|
69
|
+
['bedrock-data-automation', 'bedrock'],
|
|
70
|
+
['bedrock-data-automation-runtime', 'bedrock'],
|
|
71
|
+
['bedrock-runtime', 'bedrock'],
|
|
72
|
+
['billing', 'billing'],
|
|
73
|
+
['braket', 'braket'],
|
|
74
|
+
['cases', 'cases'],
|
|
75
|
+
['cassandra', 'cassandra'],
|
|
76
|
+
['cassandra-streams', 'cassandra'],
|
|
77
|
+
['catalog.marketplace', 'aws-marketplace'],
|
|
78
|
+
['chatbot', 'chatbot'],
|
|
79
|
+
['cleanrooms', 'cleanrooms'],
|
|
80
|
+
['cleanrooms-ml', 'cleanrooms-ml'],
|
|
81
|
+
['cloud9', 'cloud9'],
|
|
82
|
+
['cloudcontrolapi', 'cloudcontrolapi'],
|
|
83
|
+
['clouddirectory', 'clouddirectory'],
|
|
84
|
+
['cloudformation', 'cloudformation'],
|
|
85
|
+
['cloudfront-keyvaluestore', 'cloudfront-keyvaluestore'],
|
|
86
|
+
['cloudhsm', 'cloudhsm'],
|
|
87
|
+
['cloudhsmv2', 'cloudhsm'],
|
|
88
|
+
['cloudsearch', 'cloudsearch'],
|
|
89
|
+
['cloudsearchdomain', 'cloudsearch'],
|
|
90
|
+
['cloudtrail', 'cloudtrail'],
|
|
91
|
+
['cloudtrail-data', 'cloudtrail-data'],
|
|
92
|
+
['codeartifact', 'codeartifact'],
|
|
93
|
+
['codebuild', 'codebuild'],
|
|
94
|
+
['codecommit', 'codecommit'],
|
|
95
|
+
['codeconnections', 'codeconnections'],
|
|
96
|
+
['codedeploy', 'codedeploy'],
|
|
97
|
+
['codeguru-profiler', 'codeguru-profiler'],
|
|
98
|
+
['codeguru-reviewer', 'codeguru-reviewer'],
|
|
99
|
+
['codeguru-security', 'codeguru-security'],
|
|
100
|
+
['codepipeline', 'codepipeline'],
|
|
101
|
+
['codestar-connections', 'codestar-connections'],
|
|
102
|
+
['codestar-notifications', 'codestar-notifications'],
|
|
103
|
+
['cognito-identity', 'cognito-identity'],
|
|
104
|
+
['cognito-idp', 'cognito-idp'],
|
|
105
|
+
['cognito-sync', 'cognito-sync'],
|
|
106
|
+
['comprehend', 'comprehend'],
|
|
107
|
+
['comprehendmedical', 'comprehendmedical'],
|
|
108
|
+
['compute-optimizer', 'compute-optimizer'],
|
|
109
|
+
['config', 'config'],
|
|
110
|
+
['connect', 'connect'],
|
|
111
|
+
['connect-campaigns', 'connect-campaigns'],
|
|
112
|
+
['contact-lens', 'connect'],
|
|
113
|
+
['controlcatalog', 'controlcatalog'],
|
|
114
|
+
['controlplane.payment-cryptography', 'payment-cryptography'],
|
|
115
|
+
['controltower', 'controltower'],
|
|
116
|
+
['cost-optimization-hub', 'cost-optimization-hub'],
|
|
117
|
+
['cur', 'cur'],
|
|
118
|
+
['data-ats.iot', 'iotdata'],
|
|
119
|
+
['data-signer', 'signer'],
|
|
120
|
+
['data.iot', 'iotdata'],
|
|
121
|
+
['data.jobs.iot', 'iot-jobs-data'],
|
|
122
|
+
['data.mediastore', 'mediastore'],
|
|
123
|
+
['data.qapps', 'qapps'],
|
|
124
|
+
['databrew', 'databrew'],
|
|
125
|
+
['dataexchange', 'dataexchange'],
|
|
126
|
+
['datapipeline', 'datapipeline'],
|
|
127
|
+
['dataplane.payment-cryptography', 'payment-cryptography'],
|
|
128
|
+
['datasync', 'datasync'],
|
|
129
|
+
['datazone', 'datazone'],
|
|
130
|
+
['dax', 'dax'],
|
|
131
|
+
['deadline', 'deadline'],
|
|
132
|
+
['deployment-marketplace', 'aws-marketplace'],
|
|
133
|
+
['devicefarm', 'devicefarm'],
|
|
134
|
+
['devops-guru', 'devops-guru'],
|
|
135
|
+
['directconnect', 'directconnect'],
|
|
136
|
+
['discovery', 'discovery'],
|
|
137
|
+
['discovery-marketplace', 'aws-marketplace'],
|
|
138
|
+
['dlm', 'dlm'],
|
|
139
|
+
['dms', 'dms'],
|
|
140
|
+
['docdb', 'docdb'],
|
|
141
|
+
['docdb-elastic', 'docdb-elastic'],
|
|
142
|
+
['drs', 'drs'],
|
|
143
|
+
['ds', 'ds'],
|
|
144
|
+
['ds-data', 'ds-data'],
|
|
145
|
+
['dsql', 'dsql'],
|
|
146
|
+
['dynamodb', 'dynamodb'],
|
|
147
|
+
['ebs', 'ebs'],
|
|
148
|
+
['ec2', 'ec2'],
|
|
149
|
+
['ec2-instance-connect', 'ec2-instance-connect'],
|
|
150
|
+
['ecs', 'ecs'],
|
|
151
|
+
['edge.sagemaker', 'sagemaker'],
|
|
152
|
+
['eks', 'eks'],
|
|
153
|
+
['eks-auth', 'eks-auth'],
|
|
154
|
+
['elasticache', 'elasticache'],
|
|
155
|
+
['elasticbeanstalk', 'elasticbeanstalk'],
|
|
156
|
+
['elasticfilesystem', 'elasticfilesystem'],
|
|
157
|
+
['elasticloadbalancing', 'elasticloadbalancing'],
|
|
158
|
+
['elasticmapreduce', 'elasticmapreduce'],
|
|
159
|
+
['elemental-inference', 'elemental-inference'],
|
|
160
|
+
['email', 'ses'],
|
|
161
|
+
['emr-containers', 'emr-containers'],
|
|
162
|
+
['emr-serverless', 'emr-serverless'],
|
|
163
|
+
['entitlement.marketplace', 'aws-marketplace'],
|
|
164
|
+
['entityresolution', 'entityresolution'],
|
|
165
|
+
['es', 'es'],
|
|
166
|
+
['events', 'events'],
|
|
167
|
+
['evs', 'evs'],
|
|
168
|
+
['execute-api', 'execute-api'],
|
|
169
|
+
['featurestore-runtime.sagemaker', 'sagemaker'],
|
|
170
|
+
['finspace', 'finspace'],
|
|
171
|
+
['finspace-api', 'finspace-api'],
|
|
172
|
+
['firehose', 'firehose'],
|
|
173
|
+
['fis', 'fis'],
|
|
174
|
+
['fms', 'fms'],
|
|
175
|
+
['forecast', 'forecast'],
|
|
176
|
+
['forecastquery', 'forecast'],
|
|
177
|
+
['frauddetector', 'frauddetector'],
|
|
178
|
+
['freetier', 'freetier'],
|
|
179
|
+
['fsx', 'fsx'],
|
|
180
|
+
['gamelift', 'gamelift'],
|
|
181
|
+
['gameliftstreams', 'gameliftstreams'],
|
|
182
|
+
['geo', 'geo'],
|
|
183
|
+
['geo-maps', 'geo-maps'],
|
|
184
|
+
['geo-places', 'geo-places'],
|
|
185
|
+
['geo-routes', 'geo-routes'],
|
|
186
|
+
['glacier', 'glacier'],
|
|
187
|
+
['globalaccelerator', 'globalaccelerator'],
|
|
188
|
+
['glue', 'glue'],
|
|
189
|
+
['grafana', 'grafana'],
|
|
190
|
+
['greengrass', 'greengrass'],
|
|
191
|
+
['groundstation', 'groundstation'],
|
|
192
|
+
['guardduty', 'guardduty'],
|
|
193
|
+
['health-agent', 'health-agent'],
|
|
194
|
+
['healthlake', 'healthlake'],
|
|
195
|
+
['iam-toolbox', 'iam'],
|
|
196
|
+
['identity-chime', 'chime'],
|
|
197
|
+
['identitystore', 'identitystore'],
|
|
198
|
+
['imagebuilder', 'imagebuilder'],
|
|
199
|
+
['ingest.timestream', 'timestream'],
|
|
200
|
+
['inspector', 'inspector'],
|
|
201
|
+
['inspector-scan', 'inspector-scan'],
|
|
202
|
+
['inspector2', 'inspector2'],
|
|
203
|
+
['interconnect', 'interconnect'],
|
|
204
|
+
['internetmonitor', 'internetmonitor'],
|
|
205
|
+
['invoicing', 'invoicing'],
|
|
206
|
+
['iot', 'iot'],
|
|
207
|
+
['iotfleetwise', 'iotfleetwise'],
|
|
208
|
+
['iotsecuredtunneling', 'iotsecuredtunneling'],
|
|
209
|
+
['iotsitewise', 'iotsitewise'],
|
|
210
|
+
['iotthingsgraph', 'iotthingsgraph'],
|
|
211
|
+
['iottwinmaker', 'iottwinmaker'],
|
|
212
|
+
['iotwireless', 'iotwireless'],
|
|
213
|
+
['ivs', 'ivs'],
|
|
214
|
+
['ivschat', 'ivschat'],
|
|
215
|
+
['ivsrealtime', 'ivs'],
|
|
216
|
+
['job-runtime.sagemaker', 'sagemaker'],
|
|
217
|
+
['kafka', 'kafka'],
|
|
218
|
+
['kafkaconnect', 'kafkaconnect'],
|
|
219
|
+
['kendra', 'kendra'],
|
|
220
|
+
['kendra-ranking', 'kendra-ranking'],
|
|
221
|
+
['kinesis', 'kinesis'],
|
|
222
|
+
['kinesisanalytics', 'kinesisanalytics'],
|
|
223
|
+
['kinesisvideo', 'kinesisvideo'],
|
|
224
|
+
['kms', 'kms'],
|
|
225
|
+
['lakeformation', 'lakeformation'],
|
|
226
|
+
['lambda', 'lambda'],
|
|
227
|
+
['launchwizard', 'launchwizard'],
|
|
228
|
+
['license-manager', 'license-manager'],
|
|
229
|
+
['license-manager-linux-subscriptions', 'license-manager-linux-subscriptions'],
|
|
230
|
+
['license-manager-user-subscriptions', 'license-manager-user-subscriptions'],
|
|
231
|
+
['lightsail', 'lightsail'],
|
|
232
|
+
['logs', 'logs'],
|
|
233
|
+
['lookoutequipment', 'lookoutequipment'],
|
|
234
|
+
['m2', 'm2'],
|
|
235
|
+
['machinelearning', 'machinelearning'],
|
|
236
|
+
['macie2', 'macie2'],
|
|
237
|
+
['mail-manager', 'ses'],
|
|
238
|
+
['managedblockchain', 'managedblockchain'],
|
|
239
|
+
['managedblockchain-query', 'managedblockchain-query'],
|
|
240
|
+
['marketplacecommerceanalytics', 'marketplacecommerceanalytics'],
|
|
241
|
+
['media-pipelines-chime', 'chime'],
|
|
242
|
+
['mediaconnect', 'mediaconnect'],
|
|
243
|
+
['mediaconvert', 'mediaconvert'],
|
|
244
|
+
['medialive', 'medialive'],
|
|
245
|
+
['mediapackage', 'mediapackage'],
|
|
246
|
+
['mediapackage-vod', 'mediapackage-vod'],
|
|
247
|
+
['mediapackagev2', 'mediapackagev2'],
|
|
248
|
+
['mediastore', 'mediastore'],
|
|
249
|
+
['medical-imaging', 'medical-imaging'],
|
|
250
|
+
['meetings-chime', 'chime'],
|
|
251
|
+
['memory-db', 'memorydb'],
|
|
252
|
+
['messaging-chime', 'chime'],
|
|
253
|
+
['metering.marketplace', 'aws-marketplace'],
|
|
254
|
+
['metrics.sagemaker', 'sagemaker'],
|
|
255
|
+
['mgh', 'mgh'],
|
|
256
|
+
['mgn', 'mgn'],
|
|
257
|
+
['migrationhub-config', 'mgh'],
|
|
258
|
+
['migrationhub-orchestrator', 'migrationhub-orchestrator'],
|
|
259
|
+
['migrationhub-strategy', 'migrationhub-strategy'],
|
|
260
|
+
['mobileanalytics', 'mobileanalytics'],
|
|
261
|
+
['models-v2-lex', 'lex'],
|
|
262
|
+
['models.lex', 'lex'],
|
|
263
|
+
['monitoring', 'monitoring'],
|
|
264
|
+
['mpa', 'mpa'],
|
|
265
|
+
['mq', 'mq'],
|
|
266
|
+
['neptune', 'neptune'],
|
|
267
|
+
['neptune-db', 'neptune-db'],
|
|
268
|
+
['neptune-graph', 'neptune-graph'],
|
|
269
|
+
['network-firewall', 'network-firewall'],
|
|
270
|
+
['networkflowmonitor', 'networkflowmonitor'],
|
|
271
|
+
['networkmonitor', 'networkmonitor'],
|
|
272
|
+
['notifications', 'notifications'],
|
|
273
|
+
['nova-act', 'nova-act'],
|
|
274
|
+
['oam', 'oam'],
|
|
275
|
+
['observabilityadmin', 'observabilityadmin'],
|
|
276
|
+
['odb', 'odb'],
|
|
277
|
+
['oidc', 'sso-oauth'],
|
|
278
|
+
['omics', 'omics'],
|
|
279
|
+
['osis', 'osis'],
|
|
280
|
+
['outposts', 'outposts'],
|
|
281
|
+
['participant.connect', 'execute-api'],
|
|
282
|
+
['partnercentral-account', 'partnercentral-account'],
|
|
283
|
+
['partnercentral-benefits', 'partnercentral-benefits'],
|
|
284
|
+
['partnercentral-channel', 'partnercentral-channel'],
|
|
285
|
+
['partnercentral-prm', 'partnercentral'],
|
|
286
|
+
['partnercentral-selling', 'partnercentral-selling'],
|
|
287
|
+
['pca-connector-ad', 'pca-connector-ad'],
|
|
288
|
+
['pca-connector-scep', 'pca-connector-scep'],
|
|
289
|
+
['pcs', 'pcs'],
|
|
290
|
+
['personalize', 'personalize'],
|
|
291
|
+
['personalize-events', 'personalize'],
|
|
292
|
+
['personalize-runtime', 'personalize'],
|
|
293
|
+
['pi', 'pi'],
|
|
294
|
+
['pinpoint', 'mobiletargeting'],
|
|
295
|
+
['pipes', 'pipes'],
|
|
296
|
+
['polly', 'polly'],
|
|
297
|
+
['portal.sso', 'awsssoportal'],
|
|
298
|
+
['pricingplanmanager', 'pricingplanmanager'],
|
|
299
|
+
['profile', 'profile'],
|
|
300
|
+
['proton', 'proton'],
|
|
301
|
+
['qbusiness', 'qbusiness'],
|
|
302
|
+
['query.timestream', 'timestream'],
|
|
303
|
+
['quicksight', 'quicksight'],
|
|
304
|
+
['ram', 'ram'],
|
|
305
|
+
['rbin', 'rbin'],
|
|
306
|
+
['rds', 'rds'],
|
|
307
|
+
['rds-data', 'rds-data'],
|
|
308
|
+
['redshift', 'redshift'],
|
|
309
|
+
['redshift-data', 'redshift-data'],
|
|
310
|
+
['redshift-serverless', 'redshift-serverless'],
|
|
311
|
+
['refactor-spaces', 'refactor-spaces'],
|
|
312
|
+
['rekognition', 'rekognition'],
|
|
313
|
+
['reporting-marketplace', 'aws-marketplace'],
|
|
314
|
+
['repostspace', 'repostspace'],
|
|
315
|
+
['resiliencehub', 'resiliencehub'],
|
|
316
|
+
['resource-explorer-2', 'resource-explorer-2'],
|
|
317
|
+
['resource-groups', 'resource-groups'],
|
|
318
|
+
['rolesanywhere', 'rolesanywhere'],
|
|
319
|
+
['route53-recovery-cluster', 'route53-recovery-cluster'],
|
|
320
|
+
['route53-recovery-control-config', 'route53-recovery-control-config'],
|
|
321
|
+
['route53-recovery-readiness', 'route53-recovery-readiness'],
|
|
322
|
+
['route53domains', 'route53domains'],
|
|
323
|
+
['route53globalresolver', 'route53globalresolver'],
|
|
324
|
+
['route53profiles', 'route53profiles'],
|
|
325
|
+
['route53resolver', 'route53resolver'],
|
|
326
|
+
['rtbfabric', 'rtbfabric'],
|
|
327
|
+
['rum', 'rum'],
|
|
328
|
+
['runtime-v2-lex', 'lex'],
|
|
329
|
+
['runtime.lex', 'lex'],
|
|
330
|
+
['runtime.sagemaker', 'sagemaker'],
|
|
331
|
+
['s3', 's3'],
|
|
332
|
+
['s3-control', 's3'],
|
|
333
|
+
['s3-outposts', 's3-outposts'],
|
|
334
|
+
['s3files', 's3files'],
|
|
335
|
+
['s3tables', 's3tables'],
|
|
336
|
+
['s3vectors', 's3vectors'],
|
|
337
|
+
['sagemaker-geospatial', 'sagemaker-geospatial'],
|
|
338
|
+
['scheduler', 'scheduler'],
|
|
339
|
+
['schemas', 'schemas'],
|
|
340
|
+
['scn', 'scn'],
|
|
341
|
+
['sdb', 'sdb'],
|
|
342
|
+
['secretsmanager', 'secretsmanager'],
|
|
343
|
+
['security-ir', 'security-ir'],
|
|
344
|
+
['securityagent', 'securityagent'],
|
|
345
|
+
['securityhub', 'securityhub'],
|
|
346
|
+
['securitylake', 'securitylake'],
|
|
347
|
+
['serverlessrepo', 'serverlessrepo'],
|
|
348
|
+
['servicecatalog', 'servicecatalog'],
|
|
349
|
+
['servicecatalog-appregistry', 'servicecatalog'],
|
|
350
|
+
['servicediscovery', 'servicediscovery'],
|
|
351
|
+
['servicequotas', 'servicequotas'],
|
|
352
|
+
['signer', 'signer'],
|
|
353
|
+
['signin', 'signin'],
|
|
354
|
+
['sms-voice', 'sms-voice'],
|
|
355
|
+
['sms-voice.pinpoint', 'sms-voice'],
|
|
356
|
+
['snow-device-management', 'snow-device-management'],
|
|
357
|
+
['snowball', 'snowball'],
|
|
358
|
+
['sns', 'sns'],
|
|
359
|
+
['social-messaging', 'social-messaging'],
|
|
360
|
+
['sqs', 'sqs'],
|
|
361
|
+
['ssm', 'ssm'],
|
|
362
|
+
['ssm-contacts', 'ssm-contacts'],
|
|
363
|
+
['ssm-guiconnect', 'ssm-guiconnect'],
|
|
364
|
+
['ssm-incidents', 'ssm-incidents'],
|
|
365
|
+
['ssm-quicksetup', 'ssm-quicksetup'],
|
|
366
|
+
['ssm-sap', 'ssm-sap'],
|
|
367
|
+
['sso', 'sso'],
|
|
368
|
+
['states', 'states'],
|
|
369
|
+
['storagegateway', 'storagegateway'],
|
|
370
|
+
['streams.dynamodb', 'dynamodb'],
|
|
371
|
+
['sts', 'sts'],
|
|
372
|
+
['support', 'support'],
|
|
373
|
+
['supportapp', 'supportapp'],
|
|
374
|
+
['supportauthz', 'supportauthz'],
|
|
375
|
+
['sustainability', 'sustainability'],
|
|
376
|
+
['swf', 'swf'],
|
|
377
|
+
['synthetics', 'synthetics'],
|
|
378
|
+
['tagging', 'tagging'],
|
|
379
|
+
['textract', 'textract'],
|
|
380
|
+
['thinclient', 'thinclient'],
|
|
381
|
+
['timestream-influxdb', 'timestream-influxdb'],
|
|
382
|
+
['tnb', 'tnb'],
|
|
383
|
+
['transcribe', 'transcribe'],
|
|
384
|
+
['transcribestreaming', 'transcribestreaming'],
|
|
385
|
+
['transfer', 'transfer'],
|
|
386
|
+
['translate', 'translate'],
|
|
387
|
+
['trustedadvisor', 'trustedadvisor'],
|
|
388
|
+
['uxc', 'uxc'],
|
|
389
|
+
['verifiedpermissions', 'verifiedpermissions'],
|
|
390
|
+
['voice-chime', 'chime'],
|
|
391
|
+
['voiceid', 'voiceid'],
|
|
392
|
+
['vpc-lattice', 'vpc-lattice'],
|
|
393
|
+
['waf-regional', 'waf-regional'],
|
|
394
|
+
['wafv2', 'wafv2'],
|
|
395
|
+
['wellarchitected', 'wellarchitected'],
|
|
396
|
+
['wisdom', 'wisdom'],
|
|
397
|
+
['workdocs', 'workdocs'],
|
|
398
|
+
['workmail', 'workmail'],
|
|
399
|
+
['workmailmessageflow', 'workmailmessageflow'],
|
|
400
|
+
['workspaces', 'workspaces'],
|
|
401
|
+
['workspaces-instances', 'workspaces-instances'],
|
|
402
|
+
['workspaces-web', 'workspaces-web'],
|
|
403
|
+
['xray', 'xray'],
|
|
404
|
+
];
|
|
405
|
+
/** Every global AWS endpoint: the service, its host, its signing name, and the region it signs for. */
|
|
406
|
+
export const GLOBAL_SERVICES = [
|
|
407
|
+
['account', 'account.us-east-1.amazonaws.com', 'account', 'us-east-1'],
|
|
408
|
+
['billingconductor', 'billingconductor.us-east-1.amazonaws.com', 'billingconductor', 'us-east-1'],
|
|
409
|
+
['budgets', 'budgets.amazonaws.com', 'budgets', 'us-east-1'],
|
|
410
|
+
['ce', 'ce.us-east-1.amazonaws.com', 'ce', 'us-east-1'],
|
|
411
|
+
['chime', 'chime.us-east-1.amazonaws.com', 'chime', 'us-east-1'],
|
|
412
|
+
['cloudfront', 'cloudfront.amazonaws.com', 'cloudfront', 'us-east-1'],
|
|
413
|
+
['codecatalyst', 'codecatalyst.global.api.aws', 'codecatalyst', 'us-east-1'],
|
|
414
|
+
['health', 'global.health.amazonaws.com', 'health', 'us-east-1'],
|
|
415
|
+
['iam', 'iam.amazonaws.com', 'iam', 'us-east-1'],
|
|
416
|
+
['importexport', 'importexport.amazonaws.com', 'IngestionService', 'us-east-1'],
|
|
417
|
+
['networkmanager', 'networkmanager.us-west-2.amazonaws.com', 'networkmanager', 'us-west-2'],
|
|
418
|
+
['notifications-contacts', 'notifications-contacts.us-east-1.api.aws', 'notifications-contacts', 'us-east-1'],
|
|
419
|
+
['organizations', 'organizations.us-east-1.amazonaws.com', 'organizations', 'us-east-1'],
|
|
420
|
+
['route53', 'route53.amazonaws.com', 'route53', 'us-east-1'],
|
|
421
|
+
['s3', 's3.amazonaws.com', 's3', 'us-east-1'],
|
|
422
|
+
['savingsplans', 'savingsplans.amazonaws.com', 'savingsplans', 'us-east-1'],
|
|
423
|
+
['shield', 'shield.us-east-1.amazonaws.com', 'shield', 'us-east-1'],
|
|
424
|
+
['sts', 'sts.amazonaws.com', 'sts', 'us-east-1'],
|
|
425
|
+
['support', 'support.us-east-1.amazonaws.com', 'support', 'us-east-1'],
|
|
426
|
+
['tax', 'tax.us-east-1.amazonaws.com', 'tax', 'us-east-1'],
|
|
427
|
+
['waf', 'waf.amazonaws.com', 'waf', 'us-east-1'],
|
|
428
|
+
];
|
package/dist/sandbox/policy.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BUNDLES, bundleNames, checkHost } from './allowlist.js';
|
|
2
|
+
import { GLOBAL_SERVICES, REGIONAL_SERVICES } from './aws-services.js';
|
|
2
3
|
/** Services whose endpoints don't follow `<service>.<region>.amazonaws.com`. Global ones sign for us-east-1. */
|
|
3
4
|
const AWS_SERVICES = {
|
|
4
5
|
iam: { hosts: () => ['iam.amazonaws.com'], signing: 'iam', global: true },
|
|
@@ -8,26 +9,48 @@ const AWS_SERVICES = {
|
|
|
8
9
|
cloudfront: { hosts: () => ['cloudfront.amazonaws.com'], signing: 'cloudfront', global: true },
|
|
9
10
|
route53: { hosts: () => ['route53.amazonaws.com'], signing: 'route53', global: true },
|
|
10
11
|
};
|
|
12
|
+
/** In `aws.services`, every AWS service: the view role alone then decides what agents read. */
|
|
13
|
+
export const ALL_SERVICES = 'all';
|
|
11
14
|
/**
|
|
12
15
|
* One signed endpoint per host. `access: full`, because most AWS APIs are POSTs: the
|
|
13
|
-
* role itself is what allows only reads (spike 2).
|
|
16
|
+
* role itself is what allows only reads (spike 2). OpenShell signs only for endpoints
|
|
17
|
+
* named with their service, with no rule for every AWS host, so `all` names every one
|
|
18
|
+
* the AWS SDK knows (aws-services.ts), with the hosts that carry a bucket's or an
|
|
19
|
+
* account's name in front.
|
|
20
|
+
*
|
|
21
|
+
* Every service but S3 is signed with `sigv4:body`: the hash of the request's body, an
|
|
22
|
+
* empty one for a GET. OpenShell's automatic `sigv4` signs a request with neither a body
|
|
23
|
+
* nor `x-amz-content-sha256` as UNSIGNED-PAYLOAD, which only S3 accepts, so every other
|
|
24
|
+
* service's GET failed (NVIDIA/OpenShell#5375). S3 keeps it: its SDKs say how to sign.
|
|
14
25
|
*/
|
|
15
26
|
function awsEndpoints(aws) {
|
|
16
|
-
|
|
27
|
+
const signed = (host, service, region) => ({
|
|
28
|
+
host,
|
|
29
|
+
port: 443,
|
|
30
|
+
protocol: 'rest',
|
|
31
|
+
enforcement: 'enforce',
|
|
32
|
+
access: 'full',
|
|
33
|
+
credential_binding: { provider: aws.provider },
|
|
34
|
+
credential_signing: service === 's3' ? 'sigv4' : 'sigv4:body',
|
|
35
|
+
signing_service: service,
|
|
36
|
+
...(region ? { signing_region: region } : {}),
|
|
37
|
+
});
|
|
38
|
+
const named = aws.services.filter((service) => service !== ALL_SERVICES).flatMap((service) => {
|
|
17
39
|
const known = AWS_SERVICES[service];
|
|
18
40
|
const hosts = known ? known.hosts(aws.region) : [`${service}.${aws.region}.amazonaws.com`];
|
|
19
|
-
return hosts.map((host) => (
|
|
20
|
-
host,
|
|
21
|
-
port: 443,
|
|
22
|
-
protocol: 'rest',
|
|
23
|
-
enforcement: 'enforce',
|
|
24
|
-
access: 'full',
|
|
25
|
-
credential_binding: { provider: aws.provider },
|
|
26
|
-
credential_signing: 'sigv4',
|
|
27
|
-
signing_service: known?.signing ?? service,
|
|
28
|
-
...(known?.global ? { signing_region: 'us-east-1' } : {}),
|
|
29
|
-
}));
|
|
41
|
+
return hosts.map((host) => signed(host, known?.signing ?? service, known?.global ? 'us-east-1' : undefined));
|
|
30
42
|
});
|
|
43
|
+
const all = aws.services.includes(ALL_SERVICES)
|
|
44
|
+
? [
|
|
45
|
+
...REGIONAL_SERVICES.map(([prefix, service, template]) => signed((template ?? '{service}.{region}.{dnsSuffix}').replace('{service}', prefix).replace('{region}', aws.region).replace('{dnsSuffix}', 'amazonaws.com'), service)),
|
|
46
|
+
signed(`*.s3.${aws.region}.amazonaws.com`, 's3'),
|
|
47
|
+
signed(`*.s3-control.${aws.region}.amazonaws.com`, 's3'),
|
|
48
|
+
...GLOBAL_SERVICES.map(([, host, service, region]) => signed(host, service, region)),
|
|
49
|
+
]
|
|
50
|
+
: [];
|
|
51
|
+
// One rule per host, a named service's first.
|
|
52
|
+
const endpoints = [...named, ...all];
|
|
53
|
+
return endpoints.filter((endpoint, i) => endpoints.findIndex((other) => other.host === endpoint.host) === i);
|
|
31
54
|
}
|
|
32
55
|
/**
|
|
33
56
|
* Programs whose connections the rules cover. A rule also applies to the processes a
|
package/dist/setup/doctor.js
CHANGED
|
@@ -16,7 +16,7 @@ import { run } from '../util.js';
|
|
|
16
16
|
import { buildCache, removeOldAgentImages } from './images.js';
|
|
17
17
|
import { probe, stateLocation } from './probe.js';
|
|
18
18
|
/** The OpenShell release the harness is built and probed against (§17.4). */
|
|
19
|
-
export const OPENSHELL_VERSION = '0.1.
|
|
19
|
+
export const OPENSHELL_VERSION = '0.1.7';
|
|
20
20
|
/** OpenShell's AWS provider profile, at that release. */
|
|
21
21
|
const AWS_PROFILE_URL = `https://raw.githubusercontent.com/NVIDIA/OpenShell/v${OPENSHELL_VERSION}/providers/aws.yaml`;
|
|
22
22
|
/**
|
|
@@ -75,7 +75,7 @@ async function machine(options, image, report) {
|
|
|
75
75
|
else
|
|
76
76
|
report(found === OPENSHELL_VERSION ? ok('OpenShell', found) : fail('OpenShell', `${found}, but the harness is pinned to ${OPENSHELL_VERSION}`, `install OpenShell ${OPENSHELL_VERSION}`));
|
|
77
77
|
const status = await run('openshell', ['status']).catch(() => undefined);
|
|
78
|
-
report(/Status:\s*Connected/.test(status?.stdout ?? '') ? ok('OpenShell gateway', 'connected') : fail('OpenShell gateway', firstLine(status?.stdout || status?.stderr) || 'not running', 'start the gateway: `
|
|
78
|
+
report(/Status:\s*Connected/.test(status?.stdout ?? '') ? ok('OpenShell gateway', 'connected') : fail('OpenShell gateway', firstLine(status?.stdout || status?.stderr) || 'not running', 'start the gateway, a systemd user service: `systemctl --user start openshell-gateway`'));
|
|
79
79
|
const host = await run('claude', ['--version']).catch(() => undefined);
|
|
80
80
|
const hostClaude = /^(\S+)/.exec(host?.stdout ?? '')?.[1];
|
|
81
81
|
report(hostClaude ? ok('Claude Code', hostClaude) : fail('Claude Code', 'not found', 'install Claude Code: the agents\' image takes it from this machine'));
|
package/dist/setup/setup.js
CHANGED
|
@@ -220,12 +220,11 @@ async function askSettings(options) {
|
|
|
220
220
|
const view = (await ask("The agents' view role ARN (arn:aws:iam::<account>:role/harness-<project>-view): ")).trim();
|
|
221
221
|
const plan = (await ask('The CI plan role ARN: ')).trim();
|
|
222
222
|
const apply = (await ask('The CI apply role ARN: ')).trim();
|
|
223
|
-
const services = (await ask('The AWS services the project uses, comma-separated (sts, s3, iam, ...): ')).split(/[,\s]+/).filter(Boolean);
|
|
224
223
|
if (!region || !VIEW_ROLE.test(view) || !ROLE.test(plan) || !ROLE.test(apply)) {
|
|
225
224
|
say('AWS skipped: a value is missing or malformed. Add `aws` and `terraform` to harness/config.json by hand, or run `harness setup` again.');
|
|
226
225
|
}
|
|
227
226
|
else {
|
|
228
|
-
config.aws = { region, provider: awsProviderName(projectDir, config.project?.repo), services: [
|
|
227
|
+
config.aws = { region, provider: awsProviderName(projectDir, config.project?.repo), services: ['all'] };
|
|
229
228
|
config.terraform = { dir: 'iac', backendConfig: 'backend-configs/staging.hcl', varFile: 'env/staging.tfvars' };
|
|
230
229
|
changed = true;
|
|
231
230
|
viewRole = view;
|
|
@@ -334,11 +333,12 @@ async function applyFix(options, config, fix, sleep) {
|
|
|
334
333
|
const repo = config.project.repo;
|
|
335
334
|
switch (fix.kind) {
|
|
336
335
|
case 'start-gateway': {
|
|
337
|
-
|
|
336
|
+
// OpenShell's Debian package runs the gateway as a systemd user service; its CLI has no command to start it.
|
|
337
|
+
const started = await run('systemctl', ['--user', 'start', 'openshell-gateway']).catch(() => undefined);
|
|
338
338
|
if (started?.code === 0)
|
|
339
339
|
say('OpenShell: gateway started.');
|
|
340
340
|
else
|
|
341
|
-
say(`OpenShell: the gateway did not start: ${(started?.stderr || started?.stdout || '
|
|
341
|
+
say(`OpenShell: the gateway did not start: ${(started?.stderr || started?.stdout || 'systemctl is missing').trim()}`);
|
|
342
342
|
return started?.code === 0;
|
|
343
343
|
}
|
|
344
344
|
case 'create-app':
|
package/package.json
CHANGED