@kensio/yulin 1.21.31 → 1.21.32
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/dist/serve/message/sim-message-log-console.js +3 -3
- package/dist/service/apigateway/api/deployment/sim-rest-api-deployment.js +3 -3
- package/dist/service/apigateway/api/method/sim-rest-api-method.js +12 -12
- package/dist/service/apigateway/api/resource/sim-rest-api-resource.js +11 -9
- package/dist/service/apigateway/api/sim-rest-api-view.js +3 -3
- package/dist/service/apigateway/api/stage/sim-rest-api-stage.js +8 -10
- package/dist/service/apigatewayv2/api/integration/sim-http-api-integration.js +3 -3
- package/dist/service/apigatewayv2/api/route/sim-http-api-route-view.js +6 -6
- package/dist/service/apigatewayv2/api/sim-http-api-view.js +3 -3
- package/dist/service/apigatewayv2/api/stage/settings/sim-http-api-stage-route-settings.js +8 -7
- package/dist/service/apigatewayv2/api/stage/sim-http-api-stage.js +9 -9
- package/dist/service/athena/engine/sim-athena-partitioned-objects.js +7 -7
- package/dist/service/athena/sim-athena-engine.fixture.js +3 -0
- package/dist/service/athena/table/sim-athena-partition-filters.js +6 -5
- package/dist/service/backup/command/sim-backup-authorizer.js +5 -4
- package/dist/service/bedrock/response/sim-bedrock-declared-content.js +5 -10
- package/dist/service/cloudformation/stack/update/sim-cfn-stack-resource-changes.js +19 -10
- package/dist/service/cloudfront/cfn/response-headers-policy/sim-cfn-cf-rh-policy-security-values.js +2 -6
- package/dist/service/cognito/user-pool/trigger/sim-cognito-pre-sign-up-response.js +4 -7
- package/dist/service/dynamodb/command/transact/sim-dynamodb-transact-write.js +34 -25
- package/dist/service/dynamodb/secondary-index/sim-dynamodb-index-limits.js +5 -4
- package/dist/service/dynamodb/stream/sim-dynamodb-stream-shard-iterator.js +1 -3
- package/dist/service/dynamodb/time-to-live/sim-dynamodb-time-to-live.js +4 -3
- package/dist/service/iam/authorize/context/sim-iam-auth-z-allow-requirement.js +6 -6
- package/dist/service/kinesis/stream/sim-kinesis-shard-iterator.js +1 -3
- package/dist/service/lambda/destination/sim-lambda-destination-record.js +7 -7
- package/dist/service/lambda/function/policy/sim-lambda-permission.js +15 -14
- package/dist/service/lambda/metric/sim-lambda-function-metrics.js +11 -9
- package/dist/service/logs/metric/sim-logs-metric-filter.js +1 -8
- package/dist/service/route53/dns/answer/sim-route53-dns-zone-finder.js +5 -4
- package/dist/service/route53/resolve/sim-r53-zone-record-finder.js +8 -6
- package/dist/service/s3/bucket/notification/sim-s3-notification-filter.js +4 -7
- package/dist/service/s3/bucket/sim-s3-bucket.d.ts +8 -0
- package/dist/service/s3/bucket/sim-s3-bucket.js +11 -0
- package/dist/service/s3/bucket/sim-s3-key-writes.d.ts +16 -0
- package/dist/service/s3/bucket/sim-s3-key-writes.js +43 -0
- package/dist/service/s3/bucket/versioning/sim-s3-bucket-versioning.js +1 -3
- package/dist/service/s3/command/complete-multipart-upload/complete-multipart-upload.command.d.ts +2 -1
- package/dist/service/s3/command/complete-multipart-upload/complete-multipart-upload.handler.js +5 -1
- package/dist/service/s3/command/copy-object/copy-object-precondition.d.ts +23 -0
- package/dist/service/s3/command/copy-object/copy-object-precondition.js +34 -0
- package/dist/service/s3/command/copy-object/copy-object.command.d.ts +3 -1
- package/dist/service/s3/command/copy-object/copy-object.handler.d.ts +4 -0
- package/dist/service/s3/command/copy-object/copy-object.handler.js +11 -1
- package/dist/service/s3/command/object/sim-s3-write-precondition.d.ts +34 -0
- package/dist/service/s3/command/object/sim-s3-write-precondition.js +47 -0
- package/dist/service/s3/command/put-object/put-object.command.d.ts +2 -1
- package/dist/service/s3/command/put-object/put-object.handler.js +5 -1
- package/dist/service/s3/error/sim-s3.error.d.ts +10 -0
- package/dist/service/s3/error/sim-s3.error.js +12 -0
- package/dist/service/s3/object/s3-object-listing.js +4 -3
- package/dist/service/s3/serve/api/sim-s3-api-input.d.ts +4 -0
- package/dist/service/s3/serve/api/sim-s3-api-input.js +10 -0
- package/dist/service/s3/serve/api/sim-s3-api-multipart-input.js +2 -0
- package/dist/service/s3/serve/api/sim-s3-api-object-input.d.ts +6 -0
- package/dist/service/s3/serve/api/sim-s3-api-object-input.js +34 -2
- package/dist/service/s3/storage/filesystem/s3-filesystem-object-keys.js +9 -8
- package/dist/service/secretsmanager/cfn/secret/sim-cfn-secrets-manager-secret-template.test-support.js +15 -23
- package/dist/service/sqs/message/sim-sqs-message.js +3 -3
- package/dist/service/stepfunctions/machine/sim-state-machine.js +4 -3
- package/dist/util/schedule/cron/sim-cron-field-bounds.js +1 -1
- package/docs/services/s3/README.md +68 -3
- package/package.json +2 -2
|
@@ -60,14 +60,15 @@ export class FilesystemS3ObjectKeys {
|
|
|
60
60
|
nestedKeyPromises.push(this.listInDirectory(entryPath));
|
|
61
61
|
continue;
|
|
62
62
|
}
|
|
63
|
-
if (entry.isFile()) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
if (!entry.isFile()) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const key = path
|
|
67
|
+
.relative(this.directoryPath, entryPath)
|
|
68
|
+
.split(path.sep)
|
|
69
|
+
.join("/");
|
|
70
|
+
if (this.safety.isAllowedObjectKeyExtension(key)) {
|
|
71
|
+
keys.push(key);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
const nestedKeys = await Promise.all(nestedKeyPromises);
|
|
@@ -18,29 +18,21 @@ export function secretTemplate(properties = {}) {
|
|
|
18
18
|
}
|
|
19
19
|
function secretProperties(properties) {
|
|
20
20
|
const { name, description, kmsKeyId, tags, secretString } = properties;
|
|
21
|
-
const declared = {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
SecretStringTemplate: "{}",
|
|
37
|
-
GenerateStringKey: "current",
|
|
38
|
-
PasswordLength: properties.passwordLength ?? 64,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
declared["SecretString"] = secretString;
|
|
43
|
-
}
|
|
21
|
+
const declared = {
|
|
22
|
+
...(name !== undefined && { Name: name }),
|
|
23
|
+
...(description !== undefined && { Description: description }),
|
|
24
|
+
...(kmsKeyId !== undefined && { KmsKeyId: kmsKeyId }),
|
|
25
|
+
...(tags !== undefined && { Tags: [...tags] }),
|
|
26
|
+
...(secretString === undefined
|
|
27
|
+
? {
|
|
28
|
+
GenerateSecretString: {
|
|
29
|
+
SecretStringTemplate: "{}",
|
|
30
|
+
GenerateStringKey: "current",
|
|
31
|
+
PasswordLength: properties.passwordLength ?? 64,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
: { SecretString: secretString }),
|
|
35
|
+
};
|
|
44
36
|
return declared;
|
|
45
37
|
}
|
|
46
38
|
function readerResource() {
|
|
@@ -126,10 +126,10 @@ export class SimSqsMessage {
|
|
|
126
126
|
"ApproximateFirstReceiveTimestamp",
|
|
127
127
|
String(this.visibility.firstReceived.getTime()),
|
|
128
128
|
],
|
|
129
|
+
...(this.deadLetterSourceArn === undefined
|
|
130
|
+
? []
|
|
131
|
+
: [["DeadLetterQueueSourceArn", this.deadLetterSourceArn]]),
|
|
129
132
|
]);
|
|
130
|
-
if (this.deadLetterSourceArn !== undefined) {
|
|
131
|
-
values.set("DeadLetterQueueSourceArn", this.deadLetterSourceArn);
|
|
132
|
-
}
|
|
133
133
|
return values;
|
|
134
134
|
}
|
|
135
135
|
}
|
|
@@ -56,9 +56,10 @@ export class SimStateMachine {
|
|
|
56
56
|
*/
|
|
57
57
|
update(changes) {
|
|
58
58
|
this.#roleArn = changes.roleArn ?? this.#roleArn;
|
|
59
|
-
if (changes.definition
|
|
60
|
-
|
|
61
|
-
this.#parsed = changes.parsed;
|
|
59
|
+
if (changes.definition === undefined || changes.parsed === undefined) {
|
|
60
|
+
return;
|
|
62
61
|
}
|
|
62
|
+
this.#definition = changes.definition;
|
|
63
|
+
this.#parsed = changes.parsed;
|
|
63
64
|
}
|
|
64
65
|
}
|
|
@@ -531,6 +531,74 @@ reports it there.
|
|
|
531
531
|
An Object uploaded in parts gets a different form. See
|
|
532
532
|
[Uploading an Object in parts](#uploading-an-object-in-parts).
|
|
533
533
|
|
|
534
|
+
## Conditional writes
|
|
535
|
+
|
|
536
|
+
`PutObject`, `CopyObject` and `CompleteMultipartUpload` take `IfNoneMatch` and `IfMatch`, which
|
|
537
|
+
state what the key has to hold before the write goes ahead. `IfNoneMatch: "*"` writes only to a key
|
|
538
|
+
that holds nothing. `IfMatch` writes only over an Object with that ETag. A write whose condition
|
|
539
|
+
fails is refused with `PreconditionFailed` (status `412`), and the Object already under the key is
|
|
540
|
+
left as it was.
|
|
541
|
+
|
|
542
|
+
```typescript sim-s3-conditional-write
|
|
543
|
+
/**
|
|
544
|
+
* Writing a simulated S3 Object only where the key is free.
|
|
545
|
+
*/
|
|
546
|
+
|
|
547
|
+
import {
|
|
548
|
+
CopyObjectCommand,
|
|
549
|
+
CreateBucketCommand,
|
|
550
|
+
PutObjectCommand,
|
|
551
|
+
} from "@aws-sdk/client-s3";
|
|
552
|
+
import { SimAws } from "@kensio/yulin";
|
|
553
|
+
|
|
554
|
+
const simAws = new SimAws();
|
|
555
|
+
const simS3 = simAws.s3();
|
|
556
|
+
|
|
557
|
+
await simS3.createBucket(new CreateBucketCommand({ Bucket: "audio-bucket" }));
|
|
558
|
+
|
|
559
|
+
await simS3.putObject(
|
|
560
|
+
new PutObjectCommand({
|
|
561
|
+
Bucket: "audio-bucket",
|
|
562
|
+
Key: "uploads/take-1.mp3",
|
|
563
|
+
Body: "first take",
|
|
564
|
+
}),
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
568
|
+
try {
|
|
569
|
+
await simS3.copyObject(
|
|
570
|
+
new CopyObjectCommand({
|
|
571
|
+
Bucket: "audio-bucket",
|
|
572
|
+
Key: "shared/take.mp3",
|
|
573
|
+
CopySource: "audio-bucket/uploads/take-1.mp3",
|
|
574
|
+
IfNoneMatch: "*",
|
|
575
|
+
}),
|
|
576
|
+
);
|
|
577
|
+
console.log("copied");
|
|
578
|
+
} catch (error) {
|
|
579
|
+
// The second attempt finds the shared key taken.
|
|
580
|
+
if (error instanceof Error && error.name === "PreconditionFailed") {
|
|
581
|
+
console.log("already there");
|
|
582
|
+
} else {
|
|
583
|
+
throw error;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
Writes to one key run one at a time. Of several conditional writes racing for an empty key, the first
|
|
590
|
+
to finish succeeds and the rest are refused. `IfMatch` on a key holding nothing answers `NoSuchKey`. On a versioned Bucket both conditions look at
|
|
591
|
+
the current version, and a delete marker counts as nothing. `IfNoneMatch` on a write accepts only
|
|
592
|
+
`*`, and real S3 refuses anything else with `NotImplemented`.
|
|
593
|
+
|
|
594
|
+
A copy also takes conditions on its source. `CopySourceIfMatch`, `CopySourceIfNoneMatch`,
|
|
595
|
+
`CopySourceIfModifiedSince` and `CopySourceIfUnmodifiedSince` refuse the copy with
|
|
596
|
+
`PreconditionFailed` when the source does not meet them. An ETag condition outranks the date
|
|
597
|
+
condition paired with it, as RFC 7232 has it. The served endpoint reads all of these from the same
|
|
598
|
+
headers real S3 does.
|
|
599
|
+
|
|
600
|
+
A failed completion leaves the upload in place, and it can be completed again.
|
|
601
|
+
|
|
534
602
|
## Uploading an Object in parts
|
|
535
603
|
|
|
536
604
|
Yulin supports multipart upload through the SDK and served S3 endpoint. This covers the operations
|
|
@@ -834,9 +902,6 @@ See [Serve simulated S3 on localhost](#serve-simulated-s3-on-localhost) for sett
|
|
|
834
902
|
- Both Buckets have to belong to the same simulated S3. A copy across Accounts or Regions is left
|
|
835
903
|
out.
|
|
836
904
|
- A presigned copy is left out, and so is a copy reaching a Bucket through simulated CloudFront.
|
|
837
|
-
- `CopySourceIfMatch`, `CopySourceIfNoneMatch`, `CopySourceIfModifiedSince` and
|
|
838
|
-
`CopySourceIfUnmodifiedSince` are ignored. A conditional copy happens whatever the condition
|
|
839
|
-
says.
|
|
840
905
|
- `ACL` is ignored. Sim S3 models no Object ACL.
|
|
841
906
|
- A `versionId` in `CopySource` is refused with `NotImplemented`.
|
|
842
907
|
- A copy of an Object that was uploaded in parts gets a plain ETag rather than the multipart form.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kensio/yulin",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.32",
|
|
4
4
|
"description": "AWS system behaviour simulation for isolated unit testing",
|
|
5
5
|
"repository": "https://github.com/KensioSoftware/yulin",
|
|
6
6
|
"homepage": "https://yulinsim.dev/",
|
|
@@ -293,7 +293,7 @@
|
|
|
293
293
|
"eslint-plugin-jsdoc": "^64.0.1",
|
|
294
294
|
"eslint-plugin-no-secrets": "^2.3.3",
|
|
295
295
|
"eslint-plugin-security": "^4.0.1",
|
|
296
|
-
"eslint-plugin-unicorn": "^
|
|
296
|
+
"eslint-plugin-unicorn": "^75.0.0",
|
|
297
297
|
"execa": "^10.0.0",
|
|
298
298
|
"fta-cli": "^3.0.0",
|
|
299
299
|
"hyparquet": "^1.29.2",
|