From 47fd645afa0b1cdd4ee1de68a78343853302571b Mon Sep 17 00:00:00 2001 From: Chris Rybicki Date: Mon, 8 Apr 2024 12:15:22 -0400 Subject: [PATCH] fix(sdk): permissions errors are not caught in simulator (#6153) Reintroduce https://github.com/winglang/wing/pull/6079 after it was reverted by https://github.com/winglang/wing/pull/6125 in an attempt to fix https://github.com/winglang/wing/issues/6135. Fixes #6002 ## Checklist - [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted) - [x] Description explains motivation and solution - [x] Tests added (always) - [ ] Docs updated (only required for features) - [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing *By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*. --- .../04-standard-library/sim/api-reference.md | 224 +++- .../invalid/simulator_permissions.test.w | 26 + .../tests/sdk_tests/service/callbacks.test.w | 2 +- libs/wingsdk/src/cloud/bucket.ts | 2 +- libs/wingsdk/src/shared/sandbox.ts | 4 +- libs/wingsdk/src/simulator/client.ts | 16 +- libs/wingsdk/src/simulator/simulator.ts | 178 ++- libs/wingsdk/src/simulator/util.ts | 19 + libs/wingsdk/src/target-sim/api.inflight.ts | 15 +- libs/wingsdk/src/target-sim/api.ts | 6 +- libs/wingsdk/src/target-sim/app.ts | 17 +- .../wingsdk/src/target-sim/bucket.inflight.ts | 20 +- libs/wingsdk/src/target-sim/bucket.ts | 47 +- .../src/target-sim/container.inflight.ts | 32 +- libs/wingsdk/src/target-sim/container.ts | 2 +- .../src/target-sim/counter.inflight.ts | 18 +- libs/wingsdk/src/target-sim/counter.ts | 2 +- .../wingsdk/src/target-sim/domain.inflight.ts | 4 +- .../src/target-sim/endpoint.inflight.ts | 26 +- .../src/target-sim/event-mapping.inflight.ts | 33 +- libs/wingsdk/src/target-sim/event-mapping.ts | 8 +- .../src/target-sim/function.inflight.ts | 33 +- libs/wingsdk/src/target-sim/function.ts | 27 +- libs/wingsdk/src/target-sim/index.ts | 1 + .../src/target-sim/on-deploy.inflight.ts | 19 +- libs/wingsdk/src/target-sim/on-deploy.ts | 4 +- .../wingsdk/src/target-sim/policy.inflight.ts | 22 + libs/wingsdk/src/target-sim/policy.ts | 72 ++ libs/wingsdk/src/target-sim/queue.inflight.ts | 21 +- libs/wingsdk/src/target-sim/queue.ts | 17 +- .../src/target-sim/react-app.inflight.ts | 15 +- libs/wingsdk/src/target-sim/react-app.ts | 2 +- libs/wingsdk/src/target-sim/redis.inflight.ts | 7 +- libs/wingsdk/src/target-sim/redis.ts | 2 +- libs/wingsdk/src/target-sim/resource.ts | 26 +- .../src/target-sim/schedule.inflight.ts | 15 +- libs/wingsdk/src/target-sim/schedule.ts | 6 +- .../src/target-sim/schema-resources.ts | 57 +- .../wingsdk/src/target-sim/secret.inflight.ts | 16 +- libs/wingsdk/src/target-sim/secret.ts | 2 +- .../src/target-sim/service.inflight.ts | 86 +- libs/wingsdk/src/target-sim/service.ts | 81 +- libs/wingsdk/src/target-sim/state.inflight.ts | 17 +- libs/wingsdk/src/target-sim/state.ts | 2 +- libs/wingsdk/src/target-sim/table.inflight.ts | 15 +- libs/wingsdk/src/target-sim/table.ts | 2 +- .../src/target-sim/test-runner.inflight.ts | 20 +- libs/wingsdk/src/target-sim/test-runner.ts | 2 +- libs/wingsdk/src/target-sim/topic.inflight.ts | 19 +- libs/wingsdk/src/target-sim/topic.ts | 9 +- libs/wingsdk/src/target-sim/util.ts | 19 +- .../src/target-sim/website.inflight.ts | 16 +- libs/wingsdk/src/target-sim/website.ts | 2 +- libs/wingsdk/src/util/enhanced-error.ts | 3 +- .../__snapshots__/connections.test.ts.snap | 58 + libs/wingsdk/test/simulator/cleanup.test.ts | 25 +- libs/wingsdk/test/simulator/on-trace.test.ts | 2 +- libs/wingsdk/test/simulator/simulator.test.ts | 196 ++- .../target-sim/__snapshots__/api.test.ts.snap | 1064 ++++++++++++++++- .../__snapshots__/bucket.test.ts.snap | 197 ++- .../__snapshots__/counter.test.ts.snap | 56 + .../__snapshots__/file-counter.test.ts.snap | 111 +- .../__snapshots__/function.test.ts.snap | 292 ++++- .../immutable-capture.test.ts.snap | 462 +++++++ .../__snapshots__/on-deploy.test.ts.snap | 36 + .../__snapshots__/queue.test.ts.snap | 270 ++++- .../__snapshots__/redis.test.ts.snap | 8 + .../__snapshots__/schedule.test.ts.snap | 216 ++++ .../__snapshots__/secret.test.ts.snap | 8 + .../__snapshots__/service.test.ts.snap | 59 +- .../__snapshots__/table.test.ts.snap | 56 + .../__snapshots__/test.test.ts.snap | 33 + .../__snapshots__/topic-producer.test.ts.snap | 11 +- .../__snapshots__/topic.test.ts.snap | 33 + libs/wingsdk/test/target-sim/app.test.ts | 9 +- libs/wingsdk/test/target-sim/bucket.test.ts | 16 +- libs/wingsdk/test/target-sim/function.test.ts | 18 +- .../wingsdk/test/target-sim/on-deploy.test.ts | 2 +- libs/wingsdk/test/target-sim/queue.test.ts | 2 +- libs/wingsdk/test/target-sim/service.test.ts | 5 +- .../test/target-sim/topic-producer.test.ts | 7 +- libs/wingsdk/test/target-sim/util.ts | 2 +- .../test/ui/__snapshots__/ui.test.ts.snap | 4 + tools/hangar/__snapshots__/invalid.ts.snap | 26 + 84 files changed, 4336 insertions(+), 306 deletions(-) create mode 100644 examples/tests/invalid/simulator_permissions.test.w create mode 100644 libs/wingsdk/src/simulator/util.ts create mode 100644 libs/wingsdk/src/target-sim/policy.inflight.ts create mode 100644 libs/wingsdk/src/target-sim/policy.ts diff --git a/docs/docs/04-standard-library/sim/api-reference.md b/docs/docs/04-standard-library/sim/api-reference.md index 0ecb35cda5c..6749af2595a 100644 --- a/docs/docs/04-standard-library/sim/api-reference.md +++ b/docs/docs/04-standard-library/sim/api-reference.md @@ -126,6 +126,126 @@ A token that resolves to the host port of this container. --- +### Policy + +- *Implements:* ISimulatorResource + +Implementation of `sim.Policy`. + +#### Initializers + +```wing +bring sim; + +new sim.Policy(props: PolicyProps); +``` + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| props | PolicyProps | *No description.* | + +--- + +##### `props`Required + +- *Type:* PolicyProps + +--- + +#### Methods + +| **Name** | **Description** | +| --- | --- | +| addStatement | Adds a statement to the policy. | +| toSimulator | Convert this resource to a resource schema for the simulator. | + +--- + +##### `addStatement` + +```wing +addStatement(resource: IResource, op: str): void +``` + +Adds a statement to the policy. + +###### `resource`Required + +- *Type:* IResource + +--- + +###### `op`Required + +- *Type:* str + +--- + +##### `toSimulator` + +```wing +toSimulator(): BaseResourceSchema +``` + +Convert this resource to a resource schema for the simulator. + +#### Static Functions + +| **Name** | **Description** | +| --- | --- | +| onLiftType | A hook called by the Wing compiler once for each inflight host that needs to use this type inflight. | + +--- + +##### `onLiftType` + +```wing +bring sim; + +sim.Policy.onLiftType(host: IInflightHost, ops: MutArray); +``` + +A hook called by the Wing compiler once for each inflight host that needs to use this type inflight. + +The list of requested inflight methods +needed by the inflight host are given by `ops`. + +This method is commonly used for adding permissions, environment variables, or +other capabilities to the inflight host. + +###### `host`Required + +- *Type:* IInflightHost + +--- + +###### `ops`Required + +- *Type:* MutArray<str> + +--- + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| node | constructs.Node | The tree node. | + +--- + +##### `node`Required + +```wing +node: Node; +``` + +- *Type:* constructs.Node + +The tree node. + +--- + + ### State - *Implements:* ISimulatorResource @@ -436,15 +556,115 @@ A glob of local files to consider as input sources for the container, relative t --- +### PolicyProps + +Options for `sim.Policy`. + +#### Initializer + +```wing +bring sim; + +let PolicyProps = sim.PolicyProps{ ... }; +``` + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| principal | IResource | The resource to which the policy is attached. | + +--- + +##### `principal`Required + +```wing +principal: IResource; +``` + +- *Type:* IResource + +The resource to which the policy is attached. + +--- + ## Protocols +### IPolicyClient + +- *Implemented By:* IPolicyClient + +Inflight interface for `Policy`. + + + +### ISimulatorInflightHost + +- *Extends:* IInflightHost + +- *Implemented By:* ISimulatorInflightHost + +Interfaces shared by all preflight classes that host inflight code. + +#### Methods + +| **Name** | **Description** | +| --- | --- | +| addPermission | Add a simulated permission to this inflight host. | + +--- + +##### `addPermission` + +```wing +addPermission(resource: IResource, op: str): void +``` + +Add a simulated permission to this inflight host. + +###### `resource`Required + +- *Type:* IResource + +The resource to add. + +--- + +###### `op`Required + +- *Type:* str + +The action to add. + +--- + +#### Properties + +| **Name** | **Type** | **Description** | +| --- | --- | --- | +| node | constructs.Node | The tree node. | + +--- + +##### `node`Required + +```wing +node: Node; +``` + +- *Type:* constructs.Node + +The tree node. + +--- + ### ISimulatorResource - *Extends:* IResource -- *Implemented By:* Container, State, ISimulatorResource +- *Implemented By:* Container, Policy, State, ISimulatorResource -Interfaces shared by all polycon implementations (preflight classes) targeting the simulator. +Interfaces shared by all preflight classes targeting the simulator. #### Methods diff --git a/examples/tests/invalid/simulator_permissions.test.w b/examples/tests/invalid/simulator_permissions.test.w new file mode 100644 index 00000000000..81f3ab9f033 --- /dev/null +++ b/examples/tests/invalid/simulator_permissions.test.w @@ -0,0 +1,26 @@ +bring cloud; + +let buckets = [ + new cloud.Bucket() as "b1", + new cloud.Bucket() as "b2" +]; + +test "incorrect resource permission" { + // This test fails because permission is granted to b2, not b1 + lift(buckets.at(1), ["put"]); + let var i = 10; + while i > 0 { + i -= 1; + } + buckets.at(i).put("key", "value"); +} + +test "incorrect permission operation" { + // This test fails because permission is granted for "list", not "put" + lift(buckets.at(0), ["list"]); + let var i = 10; + while i > 0 { + i -= 1; + } + buckets.at(i).put("key", "value"); +} diff --git a/examples/tests/sdk_tests/service/callbacks.test.w b/examples/tests/sdk_tests/service/callbacks.test.w index 3ed3b962a62..1f35b77da80 100644 --- a/examples/tests/sdk_tests/service/callbacks.test.w +++ b/examples/tests/sdk_tests/service/callbacks.test.w @@ -50,4 +50,4 @@ if util.env("WING_TARGET") == "sim" { assert(startCounter.peek() == 0); assert(b.get(status) == stopped); } -} \ No newline at end of file +} diff --git a/libs/wingsdk/src/cloud/bucket.ts b/libs/wingsdk/src/cloud/bucket.ts index e35992a38e4..dae03e3c800 100644 --- a/libs/wingsdk/src/cloud/bucket.ts +++ b/libs/wingsdk/src/cloud/bucket.ts @@ -107,7 +107,7 @@ export class Bucket extends Resource { * Gets topic form the topics map, or creates if not exists * @param actionType */ - private getTopic(actionType: BucketEventType): Topic { + protected getTopic(actionType: BucketEventType): Topic { if (!this._topics.has(actionType)) { this._topics.set(actionType, this.createTopic(actionType)); } diff --git a/libs/wingsdk/src/shared/sandbox.ts b/libs/wingsdk/src/shared/sandbox.ts index f61d61fde6d..510b2c9e443 100644 --- a/libs/wingsdk/src/shared/sandbox.ts +++ b/libs/wingsdk/src/shared/sandbox.ts @@ -222,14 +222,14 @@ process.on("message", async (message) => { // "exit" could be emitted if the user code called process.exit(), or if we killed the process // due to a timeout or unexpected error. In any case, we reject the promise. - this.onChildExit = (code: number | null) => { + this.onChildExit = (code: number | null, signal: unknown) => { this.debugLog("Child processed stopped."); this.child = undefined; this.available = true; if (this.timeout) { clearTimeout(this.timeout); } - reject(new Error(`Process exited with code ${code}`)); + reject(new Error(`Process exited with code ${code}, signal ${signal}`)); }; if (this.options.timeout) { diff --git a/libs/wingsdk/src/simulator/client.ts b/libs/wingsdk/src/simulator/client.ts index a46262b7f05..9b223330fbd 100644 --- a/libs/wingsdk/src/simulator/client.ts +++ b/libs/wingsdk/src/simulator/client.ts @@ -35,7 +35,19 @@ function makeHttpRequest(options: HttpRequestOptions): Promise { }); } -export function makeSimulatorClient(url: string, handle: string) { +/** + * Creates a proxy object that forwards method calls to the simulator server. + * + * @param url The URL of the simulator server + * @param handle The handle for the resource we're calling methods on or getting properties from + * @param caller The handle of the resource that is making the calls + * @returns A proxy object that forwards calls to the simulator server + */ +export function makeSimulatorClient( + url: string, + handle: string, + caller: string +) { let proxy: any; let hasThenMethod = true; // assume that the object has a "then" method until proven otherwise @@ -45,7 +57,7 @@ export function makeSimulatorClient(url: string, handle: string) { } return async function (...args: any[]) { - const body: SimulatorServerRequest = { handle, method, args }; + const body: SimulatorServerRequest = { caller, handle, method, args }; const parsedUrl = new URL(url); const resp = await makeHttpRequest({ hostname: parsedUrl.hostname, diff --git a/libs/wingsdk/src/simulator/simulator.ts b/libs/wingsdk/src/simulator/simulator.ts index bb63842446b..f445875160e 100644 --- a/libs/wingsdk/src/simulator/simulator.ts +++ b/libs/wingsdk/src/simulator/simulator.ts @@ -7,14 +7,23 @@ import { Graph } from "./graph"; import { deserialize, serialize } from "./serialization"; import { resolveTokens } from "./tokens"; import { Tree } from "./tree"; +import { exists } from "./util"; import { SDK_VERSION } from "../constants"; import { TREE_FILE_PATH } from "../core"; import { readJsonSync } from "../shared/misc"; import { CONNECTIONS_FILE_PATH, Trace, TraceType } from "../std"; +import { POLICY_FQN } from "../target-sim"; +import { PolicySchemaProps } from "../target-sim/schema-resources"; const LOCALHOST_ADDRESS = "127.0.0.1"; const HANDLE_ATTRIBUTE = "handle"; +/** + * If an API call is made to a resource with name as the caller, any permissions + * checking will be skipped. Used by unit tests and the Wing Console. + */ +const ADMIN_PERMISSION = "admin"; + /** * Props for `Simulator`. */ @@ -93,6 +102,11 @@ export interface ISimulatorContext { */ readonly resourcePath: string; + /** + * The handle of the resource that is being simulated. + */ + readonly resourceHandle: string; + /** * The url that the simulator server is listening on. */ @@ -101,7 +115,7 @@ export interface ISimulatorContext { /** * Obtain a client given a resource's handle. */ - getClient(handle: string): unknown; + getClient(handle: string, asAdmin?: boolean): unknown; /** * Add a trace. Traces are breadcrumbs of information about resource @@ -186,6 +200,7 @@ export class Simulator { private _serverUrl: string | undefined; private _server: Server | undefined; private _model: Model; + private _policyRegistry: PolicyRegistry; // keeps the actual resolved state (props and attrs) of all started resources. this state is // merged in when calling `getResourceConfig()`. @@ -198,6 +213,7 @@ export class Simulator { this._running = "stopped"; this._handles = new HandleManager(); + this._policyRegistry = new PolicyRegistry(); this._traces = new Array(); this._traceSubscribers = new Array(); } @@ -380,13 +396,19 @@ export class Simulator { try { const resource = this._handles.find(handle); + await this.ensureStateDirExists(path); await resource.save(this.getResourceStateDir(path)); - this._handles.deallocate(handle); await resource.cleanup(); + this._handles.deallocate(handle); } catch (err) { console.warn(err); } + // if the resource is a policy, remove it from the policy registry + if (this.getResourceConfig(path).type === POLICY_FQN) { + this._policyRegistry.deregister(path); + } + this.addSimulatorTrace(path, { message: `${path} stopped` }); delete this.state[path]; // delete the state of the resource } @@ -453,8 +475,7 @@ export class Simulator { if (!handle) { return undefined; } - - return makeSimulatorClient(this.url, handle); + return makeSimulatorClient(this.url, handle, ADMIN_PERMISSION); } private tryGetResourceHandle(path: string): string | undefined { @@ -509,6 +530,14 @@ export class Simulator { return join(this.statedir, config.addr); } + private async ensureStateDirExists(path: string) { + const statedir = this.getResourceStateDir(path); + const statedirExists = await exists(statedir); + if (!statedirExists) { + await mkdir(statedir, { recursive: true }); + } + } + /** * Obtain a resource's visual interaction components. * @returns An array of UIComponent objects @@ -551,6 +580,43 @@ export class Simulator { return structuredClone(this._model.connections); } + private checkPermission( + callerHandle: string, + calleeHandle: string, + method: string + ): { granted: boolean; reason?: string } { + if (callerHandle === ADMIN_PERMISSION) { + return { granted: true }; + } + + const callerPath = this._handles.tryFindPath(callerHandle); + if (!callerPath) { + return { + granted: false, + reason: `(Permission checking) No caller resource with handle "${callerHandle}" found.`, + }; + } + + const calleePath = this._handles.tryFindPath(calleeHandle); + if (!calleePath) { + return { + granted: false, + reason: `(Permission checking) No callee resource with handle "${calleeHandle}" found.`, + }; + } + + if ( + this._policyRegistry.checkPermission(callerHandle, calleeHandle, method) + ) { + return { granted: true }; + } + + return { + granted: false, + reason: `Resource "${callerPath}" does not have permission to perform operation "${method}" on resource "${calleePath}".`, + }; + } + /** * Start a server that allows any resource to be accessed via HTTP. */ @@ -568,9 +634,24 @@ export class Simulator { }); req.on("end", () => { const request: SimulatorServerRequest = deserialize(body); - const { handle, method, args } = request; + const { caller, handle, method, args } = request; const resource = this._handles.tryFind(handle); + // Check if the caller has permission to call the method on the resource + const grant = this.checkPermission(caller, handle, method); + if (!grant.granted) { + res.writeHead(403, { "Content-Type": "application/json" }); + res.end( + serialize({ + error: { + message: grant.reason, + }, + }), + "utf-8" + ); + return; + } + // If we weren't able to find a resource with the given handle, it could actually // be OK if the resource is still starting up or has already been cleaned up. // In that case, we return a 500 error with a message that explains what happened. @@ -690,7 +771,6 @@ export class Simulator { } const resourceConfig = this.getResourceConfig(path); - const context = this.createContext(resourceConfig); const resolvedProps = this.resolveTokens(resourceConfig.props); @@ -711,15 +791,18 @@ export class Simulator { // create the resource based on its type // eslint-disable-next-line @typescript-eslint/no-require-imports const ResourceType = require(typeInfo.sourcePath)[typeInfo.className]; - const resourceObject = new ResourceType(resolvedProps, context); - const attrs = await resourceObject.init(); + const resourceObject = new ResourceType(resolvedProps); + + // allocate a handle for the resource so others can find it + const handle = this._handles.allocate(path, resourceObject); + + // initialize the resource with the simulator context + const context = this.createContext(resourceConfig, handle); + const attrs = await resourceObject.init(context); // save the current state await resourceObject.save(); - // allocate a handle for the resource so others can find it - const handle = this._handles.allocate(resourceObject); - // merge the attributes this.state[path].attrs = { ...this.state[path].attrs, @@ -731,16 +814,27 @@ export class Simulator { this.addSimulatorTrace(path, { message: `${resourceConfig.path} started`, }); + + // if the resource is a policy, add it to the policy registry + if (resourceConfig.type === POLICY_FQN) { + const policyProps = resolvedProps as PolicySchemaProps; + this._policyRegistry.register(resourceConfig.path, policyProps); + } } - private createContext(resourceConfig: BaseResourceSchema): ISimulatorContext { + private createContext( + resourceConfig: BaseResourceSchema, + resourceHandle: string + ): ISimulatorContext { return { simdir: this._model.simdir, statedir: join(this.statedir, resourceConfig.addr), resourcePath: resourceConfig.path, + resourceHandle: resourceHandle, serverUrl: this.url, - getClient: (handle: string) => { - return makeSimulatorClient(this.url, handle); + getClient: (calleeHandle: string, asAdmin: boolean) => { + const callerHandle = asAdmin ? ADMIN_PERMISSION : resourceHandle; + return makeSimulatorClient(this.url, calleeHandle, callerHandle); }, addTrace: (trace: Trace) => { this.addTrace(trace); @@ -944,16 +1038,19 @@ export interface ISimulatorFactory { class HandleManager { private readonly handles: Map; + private readonly paths: Map; // handle -> path private nextHandle: number; public constructor() { this.handles = new Map(); + this.paths = new Map(); this.nextHandle = 0; } - public allocate(resource: ISimulatorResourceInstance): string { + public allocate(path: string, resource: ISimulatorResourceInstance): string { const handle = `sim-${this.nextHandle++}`; this.handles.set(handle, resource); + this.paths.set(handle, path); return handle; } @@ -969,17 +1066,23 @@ class HandleManager { return this.handles.get(handle); } + public tryFindPath(handle: string): string | undefined { + return this.paths.get(handle); + } + public deallocate(handle: string): ISimulatorResourceInstance { const instance = this.handles.get(handle); if (!instance) { throw new Error(`No resource found with handle "${handle}".`); } this.handles.delete(handle); + this.paths.delete(handle); return instance; } public reset(): void { this.handles.clear(); + this.paths.clear(); this.nextHandle = 0; } } @@ -992,7 +1095,7 @@ export interface ISimulatorResourceInstance { * Perform any async initialization required by the resource. Return a map of * the resource's runtime attributes. */ - init(): Promise>; + init(ctx: ISimulatorContext): Promise>; /** * Stop the resource and clean up any physical resources it may have created @@ -1091,7 +1194,9 @@ export interface ConnectionData { * Subject to breaking changes. */ export interface SimulatorServerRequest { - /** The resource handle (an ID unique among resources in the simulation). */ + /** The handle of the resource making the request. */ + readonly caller: string; + /** The target resource handle (an ID unique among resources in the simulation). */ readonly handle: string; /** The method to call on the resource. */ readonly method: string; @@ -1109,3 +1214,42 @@ export interface SimulatorServerResponse { /** The error that occurred during the method call. */ readonly error?: any; } + +class PolicyRegistry { + private readonly policies: Record; + + constructor() { + this.policies = {}; + } + + public register(id: string, policy: PolicySchemaProps) { + if (this.policies[id]) { + throw new Error(`Policy with id ${id} already registered.`); + } + this.policies[id] = policy; + } + + public deregister(id: string) { + delete this.policies[id]; + } + + public checkPermission( + caller: string, + callee: string, + method: string + ): boolean { + for (const policy of Object.values(this.policies)) { + if (policy.principal === caller) { + for (const statement of policy.statements) { + if ( + statement.resourceHandle === callee && + statement.operation === method + ) { + return true; + } + } + } + } + return false; + } +} diff --git a/libs/wingsdk/src/simulator/util.ts b/libs/wingsdk/src/simulator/util.ts new file mode 100644 index 00000000000..16148b3cf1b --- /dev/null +++ b/libs/wingsdk/src/simulator/util.ts @@ -0,0 +1,19 @@ +import { access, constants } from "node:fs"; +import { promisify } from "node:util"; + +/** + * Check if a file exists for an specific path + * @param filePath + * @Returns Return `true` if the file exists, `false` otherwise. + */ +export async function exists(filePath: string): Promise { + try { + await promisify(access)( + filePath, + constants.F_OK | constants.R_OK | constants.W_OK //eslint-disable-line no-bitwise + ); + return true; + } catch (er) { + return false; + } +} diff --git a/libs/wingsdk/src/target-sim/api.inflight.ts b/libs/wingsdk/src/target-sim/api.inflight.ts index f53b86400c9..6a0bd4b1595 100644 --- a/libs/wingsdk/src/target-sim/api.inflight.ts +++ b/libs/wingsdk/src/target-sim/api.inflight.ts @@ -51,15 +51,14 @@ export class Api implements IApiClient, ISimulatorResourceInstance, IEventPublisher { private readonly routes: ApiRouteWithFunctionHandle[]; - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; private readonly app: express.Application; private server: Server | undefined; private url: string | undefined; private port: number | undefined; - constructor(props: ApiSchema["props"], context: ISimulatorContext) { + constructor(props: ApiSchema["props"]) { this.routes = []; - this.context = context; const { corsHeaders } = props; // Set up an express server that handles the routes. @@ -95,7 +94,15 @@ export class Api } } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; // Check for a previous state file to see if there was a port that was previously being used // if so, try to use it out of convenience let lastPort: number | undefined; diff --git a/libs/wingsdk/src/target-sim/api.ts b/libs/wingsdk/src/target-sim/api.ts index 5cdb5cddc0d..ea60d2ccd62 100644 --- a/libs/wingsdk/src/target-sim/api.ts +++ b/libs/wingsdk/src/target-sim/api.ts @@ -3,6 +3,7 @@ import { Construct } from "constructs"; import { App } from "./app"; import { EventMapping } from "./event-mapping"; import { Function } from "./function"; +import { Policy } from "./policy"; import { ISimulatorResource } from "./resource"; import { ApiSchema, ApiRoute } from "./schema-resources"; import { simulatorAttrToken } from "./tokens"; @@ -24,6 +25,7 @@ export class Api extends cloud.Api implements ISimulatorResource { > = {}; private readonly endpoint: cloud.Endpoint; + private readonly policy: Policy; constructor(scope: Construct, id: string, props: cloud.ApiProps = {}) { super(scope, id, props); @@ -34,6 +36,7 @@ export class Api extends cloud.Api implements ISimulatorResource { simulatorAttrToken(this, "url"), { label: `Api ${this.node.path}` } ); + this.policy = new Policy(this, "Policy", { principal: this }); } protected get _endpoint(): cloud.Endpoint { @@ -116,6 +119,7 @@ export class Api extends cloud.Api implements ISimulatorResource { target: fn, name: `${method.toLowerCase()}()`, }); + this.policy.addStatement(fn, cloud.FunctionInflightMethods.INVOKE); } /** @@ -245,7 +249,7 @@ export class Api extends cloud.Api implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/app.ts b/libs/wingsdk/src/target-sim/app.ts index 8595c37bc6a..140dddb7454 100644 --- a/libs/wingsdk/src/target-sim/app.ts +++ b/libs/wingsdk/src/target-sim/app.ts @@ -9,13 +9,14 @@ import { Endpoint } from "./endpoint"; import { EVENT_MAPPING_FQN } from "./event-mapping"; import { Function } from "./function"; import { OnDeploy } from "./on-deploy"; +import { POLICY_FQN, Policy } from "./policy"; import { Queue } from "./queue"; import { ReactApp } from "./react-app"; import { Redis } from "./redis"; import { ISimulatorResource, isSimulatorResource } from "./resource"; import { Schedule } from "./schedule"; import { Secret } from "./secret"; -import { Service } from "./service"; +import { SERVICE_HELPER_FQN, Service, ServiceHelper } from "./service"; import { STATE_FQN, State } from "./state"; import { Table } from "./table"; import { TestRunner } from "./test-runner"; @@ -59,12 +60,14 @@ const SIMULATOR_CLASS_DATA = { [EVENT_MAPPING_FQN]: "EventMapping", [FUNCTION_FQN]: "Function", [ON_DEPLOY_FQN]: "OnDeploy", + [POLICY_FQN]: "Policy", [QUEUE_FQN]: "Queue", [REACT_APP_FQN]: "ReactApp", [REDIS_FQN]: "Redis", [SCHEDULE_FQN]: "Schedule", [SECRET_FQN]: "Secret", [SERVICE_FQN]: "Service", + [SERVICE_HELPER_FQN]: "ServiceHelper", [STATE_FQN]: "State", [SIM_CONTAINER_FQN]: "Container", [TABLE_FQN]: "Table", @@ -119,6 +122,9 @@ export class App extends core.App { case ON_DEPLOY_FQN: return require.resolve("./on-deploy.inflight"); + case POLICY_FQN: + return require.resolve("./policy.inflight"); + case QUEUE_FQN: return require.resolve("./queue.inflight"); @@ -137,6 +143,9 @@ export class App extends core.App { case SERVICE_FQN: return require.resolve("./service.inflight"); + case SERVICE_HELPER_FQN: + return require.resolve("./service.inflight"); + case STATE_FQN: return require.resolve("./state.inflight"); @@ -184,6 +193,9 @@ export class App extends core.App { case ON_DEPLOY_FQN: return OnDeploy; + case POLICY_FQN: + return Policy; + case QUEUE_FQN: return Queue; @@ -202,6 +214,9 @@ export class App extends core.App { case SERVICE_FQN: return Service; + case SERVICE_HELPER_FQN: + return ServiceHelper; + case STATE_FQN: return State; diff --git a/libs/wingsdk/src/target-sim/bucket.inflight.ts b/libs/wingsdk/src/target-sim/bucket.inflight.ts index f4178e6e50b..18cb87ed8f2 100644 --- a/libs/wingsdk/src/target-sim/bucket.inflight.ts +++ b/libs/wingsdk/src/target-sim/bucket.inflight.ts @@ -28,23 +28,31 @@ import { Datetime, Json, TraceType } from "../std"; export const METADATA_FILENAME = "metadata.json"; export class Bucket implements IBucketClient, ISimulatorResourceInstance { - private readonly _fileDir: string; - private readonly context: ISimulatorContext; + private _fileDir!: string; + private _context: ISimulatorContext | undefined; private readonly initialObjects: Record; private readonly _public: boolean; private readonly topicHandlers: Partial>; private _metadata: Map; - public constructor(props: BucketSchema["props"], context: ISimulatorContext) { - this._fileDir = join(context.statedir, "files"); - this.context = context; + public constructor(props: BucketSchema["props"]) { this.initialObjects = props.initialObjects ?? {}; this._public = props.public ?? false; this.topicHandlers = props.topics; this._metadata = new Map(); } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; + this._fileDir = join(context.statedir, "files"); + const fileDirExists = await exists(this._fileDir); if (!fileDirExists) { await fs.promises.mkdir(this._fileDir, { recursive: true }); diff --git a/libs/wingsdk/src/target-sim/bucket.ts b/libs/wingsdk/src/target-sim/bucket.ts index afb13c5573b..0d263dbfec1 100644 --- a/libs/wingsdk/src/target-sim/bucket.ts +++ b/libs/wingsdk/src/target-sim/bucket.ts @@ -1,5 +1,6 @@ import { join } from "path"; import { Construct } from "constructs"; +import { Policy } from "./policy"; import { ISimulatorResource } from "./resource"; import { BucketSchema } from "./schema-resources"; import { simulatorHandleToken } from "./tokens"; @@ -16,10 +17,13 @@ import { IInflightHost } from "../std"; export class Bucket extends cloud.Bucket implements ISimulatorResource { private readonly public: boolean; private readonly initialObjects: Record = {}; + private readonly policy: Policy; + constructor(scope: Construct, id: string, props: cloud.BucketProps = {}) { super(scope, id, props); this.public = props.public ?? false; + this.policy = new Policy(this, "Policy", { principal: this }); } /** @internal */ @@ -41,6 +45,7 @@ export class Bucket extends cloud.Bucket implements ISimulatorResource { cloud.BucketInflightMethods.RENAME, ]; } + /** * Iterates over the topics and supply their sim handler * @returns an object of Bucket event types (keys) and their topic handlers (values) @@ -59,6 +64,46 @@ export class Bucket extends cloud.Bucket implements ISimulatorResource { this.initialObjects[key] = body; } + public onCreate( + fn: cloud.IBucketEventHandler, + opts?: cloud.BucketOnCreateOptions | undefined + ): void { + super.onCreate(fn, opts); + const topic = this.getTopic(cloud.BucketEventType.CREATE); + this.policy.addStatement(topic, cloud.TopicInflightMethods.PUBLISH); + } + + public onDelete( + fn: cloud.IBucketEventHandler, + opts?: cloud.BucketOnDeleteOptions | undefined + ): void { + super.onDelete(fn, opts); + const topic = this.getTopic(cloud.BucketEventType.DELETE); + this.policy.addStatement(topic, cloud.TopicInflightMethods.PUBLISH); + } + + public onUpdate( + fn: cloud.IBucketEventHandler, + opts?: cloud.BucketOnUpdateOptions | undefined + ): void { + super.onUpdate(fn, opts); + const topic = this.getTopic(cloud.BucketEventType.UPDATE); + this.policy.addStatement(topic, cloud.TopicInflightMethods.PUBLISH); + } + + public onEvent( + fn: cloud.IBucketEventHandler, + opts?: cloud.BucketOnEventOptions + ): void { + super.onEvent(fn, opts); + const createTopic = this.getTopic(cloud.BucketEventType.CREATE); + this.policy.addStatement(createTopic, cloud.TopicInflightMethods.PUBLISH); + const deleteTopic = this.getTopic(cloud.BucketEventType.DELETE); + this.policy.addStatement(deleteTopic, cloud.TopicInflightMethods.PUBLISH); + const updateTopic = this.getTopic(cloud.BucketEventType.UPDATE); + this.policy.addStatement(updateTopic, cloud.TopicInflightMethods.PUBLISH); + } + protected eventHandlerLocation(): string { return join(__dirname, "bucket.onevent.inflight.js"); } @@ -79,7 +124,7 @@ export class Bucket extends cloud.Bucket implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/container.inflight.ts b/libs/wingsdk/src/target-sim/container.inflight.ts index 2edab95d93c..b8df58b31f5 100644 --- a/libs/wingsdk/src/target-sim/container.inflight.ts +++ b/libs/wingsdk/src/target-sim/container.inflight.ts @@ -12,27 +12,23 @@ import { Util } from "../util"; export class Container implements IContainerClient, ISimulatorResourceInstance { private readonly imageTag: string; private readonly containerName: string; + private _context: ISimulatorContext | undefined; - public constructor( - private readonly props: ContainerSchema["props"], - private readonly context: ISimulatorContext - ) { + public constructor(private readonly props: ContainerSchema["props"]) { this.imageTag = props.imageTag; this.containerName = `wing-container-${Util.ulid()}`; } - private log(message: string) { - this.context.addTrace({ - data: { message }, - sourcePath: this.context.resourcePath, - sourceType: "container", - timestamp: new Date().toISOString(), - type: TraceType.RESOURCE, //system messages that will be displayed on debug mode only - }); + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; } - public async init(): Promise { + public async init(context: ISimulatorContext): Promise { + this._context = context; // if this a reference to a local directory, build the image from a docker file if (isPath(this.props.image)) { // check if the image is already built @@ -134,6 +130,16 @@ export class Container implements IContainerClient, ISimulatorResourceInstance { public async plan() { return UpdatePlan.AUTO; } + + private log(message: string) { + this.context.addTrace({ + data: { message }, + sourcePath: this.context.resourcePath, + sourceType: "container", + timestamp: new Date().toISOString(), + type: TraceType.RESOURCE, + }); + } } async function waitUntil(predicate: () => Promise) { diff --git a/libs/wingsdk/src/target-sim/container.ts b/libs/wingsdk/src/target-sim/container.ts index 947553686de..af4022f5392 100644 --- a/libs/wingsdk/src/target-sim/container.ts +++ b/libs/wingsdk/src/target-sim/container.ts @@ -119,7 +119,7 @@ export class Container extends Resource implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/counter.inflight.ts b/libs/wingsdk/src/target-sim/counter.inflight.ts index 3e52273cb8a..d4ef6ce46de 100644 --- a/libs/wingsdk/src/target-sim/counter.inflight.ts +++ b/libs/wingsdk/src/target-sim/counter.inflight.ts @@ -14,18 +14,22 @@ const VALUES_FILENAME = "values.json"; export class Counter implements ICounterClient, ISimulatorResourceInstance { private values: Map; private initial: number; - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; - public constructor( - props: CounterSchema["props"], - context: ISimulatorContext - ) { + public constructor(props: CounterSchema["props"]) { this.initial = props.initial ?? 0; this.values = new Map().set("default", this.initial); - this.context = context; } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; const valuesFile = join(this.context.statedir, VALUES_FILENAME); const valueFilesExists = await exists(valuesFile); if (valueFilesExists) { diff --git a/libs/wingsdk/src/target-sim/counter.ts b/libs/wingsdk/src/target-sim/counter.ts index a70abfabdf6..0c9c15f5b9e 100644 --- a/libs/wingsdk/src/target-sim/counter.ts +++ b/libs/wingsdk/src/target-sim/counter.ts @@ -43,7 +43,7 @@ export class Counter extends cloud.Counter implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/domain.inflight.ts b/libs/wingsdk/src/target-sim/domain.inflight.ts index 22aa307a33a..b04c0ae80de 100644 --- a/libs/wingsdk/src/target-sim/domain.inflight.ts +++ b/libs/wingsdk/src/target-sim/domain.inflight.ts @@ -7,8 +7,8 @@ import { } from "../simulator"; export class Domain implements IDomainClient, ISimulatorResourceInstance { - constructor(_props: DomainSchema["props"], _context: ISimulatorContext) {} - public async init(): Promise> { + constructor(_props: DomainSchema["props"]) {} + public async init(_context: ISimulatorContext): Promise> { return {}; } diff --git a/libs/wingsdk/src/target-sim/endpoint.inflight.ts b/libs/wingsdk/src/target-sim/endpoint.inflight.ts index 6b6df4eaea3..fc3188c635a 100644 --- a/libs/wingsdk/src/target-sim/endpoint.inflight.ts +++ b/libs/wingsdk/src/target-sim/endpoint.inflight.ts @@ -29,11 +29,19 @@ export class Endpoint implements IEndpointClient, ISimulatorResourceInstance { private connectResponse?: ConnectResponse; private lastSubdomain?: string; private status: EndpointExposeStatus = "disconnected"; - constructor( - private readonly _props: EndpointSchema["props"], - private readonly _context: ISimulatorContext - ) {} - public async init(): Promise { + private _context: ISimulatorContext | undefined; + + constructor(private readonly _props: EndpointSchema["props"]) {} + + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; const state: StateFileContents = await this.loadState(); if (state.subdomain) { await this.connect(state.subdomain); @@ -81,11 +89,11 @@ export class Endpoint implements IEndpointClient, ISimulatorResourceInstance { private async loadState(): Promise { const stateFileExists = await exists( - join(this._context.statedir, STATE_FILENAME) + join(this.context.statedir, STATE_FILENAME) ); if (stateFileExists) { const stateFileContents = await readFile( - join(this._context.statedir, STATE_FILENAME), + join(this.context.statedir, STATE_FILENAME), "utf-8" ); return JSON.parse(stateFileContents); @@ -96,14 +104,14 @@ export class Endpoint implements IEndpointClient, ISimulatorResourceInstance { private async saveState(state: StateFileContents): Promise { writeFileSync( - join(this._context.statedir, STATE_FILENAME), + join(this.context.statedir, STATE_FILENAME), JSON.stringify(state) ); } private async connect(subdomain?: string) { try { - await this._context.withTrace({ + await this.context.withTrace({ message: `Creating tunnel for endpoint. ${ subdomain ? `Using subdomain: ${subdomain}` : "" }`, diff --git a/libs/wingsdk/src/target-sim/event-mapping.inflight.ts b/libs/wingsdk/src/target-sim/event-mapping.inflight.ts index c0c2b19956f..d1b7239405f 100644 --- a/libs/wingsdk/src/target-sim/event-mapping.inflight.ts +++ b/libs/wingsdk/src/target-sim/event-mapping.inflight.ts @@ -3,34 +3,47 @@ import { EventMappingAttributes, EventMappingSchema, EventSubscription, - FunctionHandle, - PublisherHandle, + ResourceHandle, } from "./schema-resources"; import { ISimulatorContext } from "../simulator"; import { ISimulatorResourceInstance, UpdatePlan } from "../simulator/simulator"; export class EventMapping implements ISimulatorResourceInstance { - private readonly publisher: PublisherHandle; - private readonly subscriber: FunctionHandle; + private readonly publisher: ResourceHandle; + private readonly subscriber: ResourceHandle; private readonly eventSubscription: EventSubscription; - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; - constructor(props: EventMappingSchema["props"], context: ISimulatorContext) { + constructor(props: EventMappingSchema["props"]) { this.publisher = props.publisher; this.subscriber = props.subscriber; this.eventSubscription = props.subscriptionProps; + } - this.context = context; + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; } - public async init(): Promise { - const client = this.context.getClient(this.publisher) as IEventPublisher; + public async init( + context: ISimulatorContext + ): Promise { + this._context = context; + const client = this.context.getClient( + this.publisher, + true + ) as IEventPublisher; await client.addEventSubscription(this.subscriber, this.eventSubscription); return {}; } public async cleanup(): Promise { - const client = this.context.getClient(this.publisher) as IEventPublisher; + const client = this.context.getClient( + this.publisher, + true + ) as IEventPublisher; await client.removeEventSubscription(this.subscriber); } diff --git a/libs/wingsdk/src/target-sim/event-mapping.ts b/libs/wingsdk/src/target-sim/event-mapping.ts index b2e7770523d..4c907613698 100644 --- a/libs/wingsdk/src/target-sim/event-mapping.ts +++ b/libs/wingsdk/src/target-sim/event-mapping.ts @@ -3,7 +3,7 @@ import { ISimulatorResource } from "./resource"; import { EventMappingSchema, EventSubscription, - FunctionHandle, + ResourceHandle, } from "./schema-resources"; import { simulatorHandleToken } from "./tokens"; import { bindSimulatorResource, makeSimulatorJsClient } from "./util"; @@ -24,7 +24,7 @@ export interface IEventPublisher extends ISimulatorResourceInstance { * @param subscriptionProps additional subscription properties */ addEventSubscription: ( - subscriber: FunctionHandle, + subscriber: ResourceHandle, subscriptionProps: EventSubscription ) => Promise; @@ -33,7 +33,7 @@ export interface IEventPublisher extends ISimulatorResourceInstance { * @param subscriber the subscriber function * @param subscriptionProps additional subscription properties */ - removeEventSubscription: (subscriber: FunctionHandle) => Promise; + removeEventSubscription: (subscriber: ResourceHandle) => Promise; } export const EVENT_MAPPING_FQN = fqnForType("sim.EventMapping"); @@ -87,7 +87,7 @@ export class EventMapping extends Resource implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/function.inflight.ts b/libs/wingsdk/src/target-sim/function.inflight.ts index b4d0258f3c4..62cd4440af3 100644 --- a/libs/wingsdk/src/target-sim/function.inflight.ts +++ b/libs/wingsdk/src/target-sim/function.inflight.ts @@ -11,29 +11,37 @@ import { import { TraceType } from "../std"; export class Function implements IFunctionClient, ISimulatorResourceInstance { - private readonly originalFile: string; + private readonly sourceCodeFile: string; + private originalFile!: string; private bundle: Bundle | undefined; private readonly env: Record; - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; private readonly timeout: number; private readonly maxWorkers: number; private readonly workers = new Array(); - private createBundlePromise: Promise; + private createBundlePromise!: Promise; - constructor(props: FunctionSchema["props"], context: ISimulatorContext) { + constructor(props: FunctionSchema["props"]) { + this.sourceCodeFile = props.sourceCodeFile; if (props.sourceCodeLanguage !== "javascript") { throw new Error("Only JavaScript is supported"); } - this.originalFile = path.resolve(context.simdir, props.sourceCodeFile); this.env = props.environmentVariables ?? {}; - this.context = context; this.timeout = props.timeout; this.maxWorkers = props.concurrency; + } - this.createBundlePromise = this.createBundle(); + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; } - public async init(): Promise { + public async init(context: ISimulatorContext): Promise { + this._context = context; + this.originalFile = path.resolve(context.simdir, this.sourceCodeFile); + this.createBundlePromise = this.createBundle(); return {}; } @@ -83,12 +91,14 @@ export class Function implements IFunctionClient, ISimulatorResourceInstance { ); } process.nextTick(() => { - // If the call fails, we log the error and continue since we've already - // handed control back to the caller. void worker.call("handler", payload).catch((e) => { + // If the call fails, we log the error and continue since we've already + // handed control back to the caller. this.context.addTrace({ data: { - message: `InvokeAsync (payload=${JSON.stringify(payload)}).`, + message: `InvokeAsync (payload=${JSON.stringify( + payload + )}) failure.`, status: "failure", error: e, }, @@ -143,6 +153,7 @@ export class Function implements IFunctionClient, ISimulatorResourceInstance { return new Sandbox(this.bundle.entrypointPath, { env: { ...this.env, + WING_SIMULATOR_CALLER: this.context.resourceHandle, WING_SIMULATOR_URL: this.context.serverUrl, }, timeout: this.timeout, diff --git a/libs/wingsdk/src/target-sim/function.ts b/libs/wingsdk/src/target-sim/function.ts index 3a77d1d7951..b106cf732a4 100644 --- a/libs/wingsdk/src/target-sim/function.ts +++ b/libs/wingsdk/src/target-sim/function.ts @@ -1,12 +1,13 @@ import { relative } from "path"; import { Construct } from "constructs"; -import { ISimulatorResource } from "./resource"; +import { Policy } from "./policy"; +import { ISimulatorInflightHost, ISimulatorResource } from "./resource"; import { FunctionSchema } from "./schema-resources"; import { bindSimulatorResource, makeSimulatorJsClient } from "./util"; import * as cloud from "../cloud"; import { App } from "../core"; import { BaseResourceSchema } from "../simulator/simulator"; -import { IInflightHost } from "../std"; +import { IInflightHost, IResource } from "../std"; import { Duration } from "../std/duration"; export const ENV_WING_SIM_INFLIGHT_RESOURCE_PATH = @@ -19,9 +20,15 @@ export const ENV_WING_SIM_INFLIGHT_RESOURCE_TYPE = * * @inflight `@winglang/sdk.cloud.IFunctionClient` */ -export class Function extends cloud.Function implements ISimulatorResource { +export class Function + extends cloud.Function + implements ISimulatorResource, ISimulatorInflightHost +{ private readonly timeout: Duration; private readonly concurrency: number; + public readonly policy: Policy; + public _liftMap = undefined; + constructor( scope: Construct, id: string, @@ -33,6 +40,11 @@ export class Function extends cloud.Function implements ISimulatorResource { // props.memory is unused since we are not simulating it this.timeout = props.timeout ?? Duration.fromMinutes(1); this.concurrency = props.concurrency ?? 100; + this.policy = new Policy(this, "Policy", { principal: this }); + } + + public addPermission(resource: IResource, op: string): void { + this.policy.addStatement(resource, op); } public toSimulator(): BaseResourceSchema { @@ -62,7 +74,7 @@ export class Function extends cloud.Function implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } @@ -71,3 +83,10 @@ export class Function extends cloud.Function implements ISimulatorResource { return makeSimulatorJsClient(__filename, this); } } + +/** + * Simulator-specific inflight methods for `cloud.Function`. + */ +export enum FunctionInflightMethods { + HAS_AVAILABLE_WORKERS = "hasAvailableWorkers", +} diff --git a/libs/wingsdk/src/target-sim/index.ts b/libs/wingsdk/src/target-sim/index.ts index dd8a337a355..7b8fd8ebf68 100644 --- a/libs/wingsdk/src/target-sim/index.ts +++ b/libs/wingsdk/src/target-sim/index.ts @@ -1,4 +1,5 @@ // only include here types that we want to expose in userland export * from "./container"; +export * from "./policy"; export * from "./resource"; export * from "./state"; diff --git a/libs/wingsdk/src/target-sim/on-deploy.inflight.ts b/libs/wingsdk/src/target-sim/on-deploy.inflight.ts index 8184d522013..2e3fe927cc6 100644 --- a/libs/wingsdk/src/target-sim/on-deploy.inflight.ts +++ b/libs/wingsdk/src/target-sim/on-deploy.inflight.ts @@ -8,21 +8,17 @@ import { export class OnDeploy implements IOnDeployClient, ISimulatorResourceInstance { private functionHandle: string; - private readonly context: ISimulatorContext; - public constructor( - props: OnDeploySchema["props"], - context: ISimulatorContext - ) { + public constructor(props: OnDeploySchema["props"]) { this.functionHandle = props.functionHandle; - this.context = context; } - public async init(): Promise { - const functionClient = this.context.getClient( - this.functionHandle + public async init(context: ISimulatorContext): Promise { + const functionClient = context.getClient( + this.functionHandle, + true ) as IFunctionClient; - await this.context.withTrace({ + await context.withTrace({ message: "OnDeploy invoked.", activity: async () => { return functionClient.invoke(); @@ -36,6 +32,7 @@ export class OnDeploy implements IOnDeployClient, ISimulatorResourceInstance { public async save(): Promise {} public async plan() { - return UpdatePlan.AUTO; + // OnDeploy runs on every deployment, so always replace + return UpdatePlan.REPLACE; } } diff --git a/libs/wingsdk/src/target-sim/on-deploy.ts b/libs/wingsdk/src/target-sim/on-deploy.ts index 6ce6c767624..8d55e3ff565 100644 --- a/libs/wingsdk/src/target-sim/on-deploy.ts +++ b/libs/wingsdk/src/target-sim/on-deploy.ts @@ -1,4 +1,5 @@ import { Construct } from "constructs"; +import { Function as SimFunction } from "./function"; import { OnDeploySchema } from "./schema-resources"; import { simulatorHandleToken } from "./tokens"; import { bindSimulatorResource, makeSimulatorJsClient } from "./util"; @@ -20,6 +21,7 @@ export class OnDeploy extends cloud.OnDeploy { Node.of(this.fn).sourceModule = SDK_SOURCE_MODULE; this.node.addDependency(this.fn); + this.node.addDependency((this.fn as SimFunction).policy); for (const c of props.executeBefore ?? []) { c.node.addDependency(this); @@ -44,7 +46,7 @@ export class OnDeploy extends cloud.OnDeploy { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/policy.inflight.ts b/libs/wingsdk/src/target-sim/policy.inflight.ts new file mode 100644 index 00000000000..7c05110d0f0 --- /dev/null +++ b/libs/wingsdk/src/target-sim/policy.inflight.ts @@ -0,0 +1,22 @@ +import { IPolicyClient } from "./policy"; +import { PolicySchema } from "./schema-resources"; +import { + ISimulatorContext, + ISimulatorResourceInstance, + UpdatePlan, +} from "../simulator"; + +export class Policy implements IPolicyClient, ISimulatorResourceInstance { + constructor(_props: PolicySchema["props"]) {} + public async init(_context: ISimulatorContext): Promise> { + return {}; + } + + public async cleanup(): Promise {} + + public async save(): Promise {} + + public async plan(): Promise { + return UpdatePlan.AUTO; + } +} diff --git a/libs/wingsdk/src/target-sim/policy.ts b/libs/wingsdk/src/target-sim/policy.ts new file mode 100644 index 00000000000..7c264237e48 --- /dev/null +++ b/libs/wingsdk/src/target-sim/policy.ts @@ -0,0 +1,72 @@ +import { Construct } from "constructs"; +import { ISimulatorResource } from "./resource"; +import { PolicySchema, PolicyStatement } from "./schema-resources"; +import { simulatorHandleToken } from "./tokens"; +import { fqnForType } from "../constants"; +import { BaseResourceSchema } from "../simulator"; +import { IResource, Node, Resource } from "../std"; + +export const POLICY_FQN = fqnForType("sim.Policy"); + +/** + * Options for `sim.Policy`. + */ +export interface PolicyProps { + /** + * The resource to which the policy is attached. + */ + readonly principal: IResource; +} + +/** + * Implementation of `sim.Policy`. + */ +export class Policy extends Resource implements ISimulatorResource { + private readonly statements: Map> = new Map(); + private readonly principal: IResource; + constructor(scope: Construct, id: string, props: PolicyProps) { + super(scope, id); + this.principal = props.principal; + Node.of(this).hidden = true; + Node.of(this).title = "Policy"; + Node.of(this).description = "A simulated resource policy"; + } + + /** + * Adds a statement to the policy. + */ + public addStatement(resource: IResource, op: string): void { + if (!this.statements.has(resource)) { + this.statements.set(resource, new Set()); + } + this.statements.get(resource)!.add(op); + } + + public toSimulator(): BaseResourceSchema { + const statements: Array = []; + for (const [resource, ops] of this.statements.entries()) { + for (const op of ops) { + statements.push({ + resourceHandle: simulatorHandleToken(resource), + operation: op, + }); + } + } + const schema: PolicySchema = { + type: POLICY_FQN, + path: this.node.path, + addr: this.node.addr, + props: { + principal: simulatorHandleToken(this.principal), + statements, + }, + attrs: {} as any, + }; + return schema; + } +} + +/** + * Inflight interface for `Policy`. + */ +export interface IPolicyClient {} diff --git a/libs/wingsdk/src/target-sim/queue.inflight.ts b/libs/wingsdk/src/target-sim/queue.inflight.ts index 3ab1683a2e9..ecd19aa7659 100644 --- a/libs/wingsdk/src/target-sim/queue.inflight.ts +++ b/libs/wingsdk/src/target-sim/queue.inflight.ts @@ -5,7 +5,7 @@ import { QueueSchema, QueueSubscriber, EventSubscription, - FunctionHandle, + ResourceHandle, } from "./schema-resources"; import { IFunctionClient, IQueueClient, QUEUE_FQN } from "../cloud"; import { @@ -21,18 +21,25 @@ export class Queue private readonly messages = new Array(); private readonly subscribers = new Array(); private readonly processLoop: LoopController; - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; private readonly timeoutSeconds: number; private readonly retentionPeriod: number; - constructor(props: QueueSchema["props"], context: ISimulatorContext) { + constructor(props: QueueSchema["props"]) { this.timeoutSeconds = props.timeout; this.retentionPeriod = props.retentionPeriod; this.processLoop = runEvery(100, async () => this.processMessages()); // every 0.1 seconds - this.context = context; } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; return {}; } @@ -47,7 +54,7 @@ export class Queue } public async addEventSubscription( - subscriber: FunctionHandle, + subscriber: ResourceHandle, subscriptionProps: EventSubscription ): Promise { const s = { @@ -58,7 +65,7 @@ export class Queue } public async removeEventSubscription( - subscriber: FunctionHandle + subscriber: ResourceHandle ): Promise { const index = this.subscribers.findIndex( (s) => s.functionHandle === subscriber diff --git a/libs/wingsdk/src/target-sim/queue.ts b/libs/wingsdk/src/target-sim/queue.ts index 632ea5dba0e..52077d72a30 100644 --- a/libs/wingsdk/src/target-sim/queue.ts +++ b/libs/wingsdk/src/target-sim/queue.ts @@ -2,7 +2,11 @@ import { join } from "path"; import { Construct } from "constructs"; import { App } from "./app"; import { EventMapping } from "./event-mapping"; -import { Function } from "./function"; +import { + Function, + FunctionInflightMethods as SimFunctionInflightMethods, +} from "./function"; +import { Policy } from "./policy"; import { ISimulatorResource } from "./resource"; import { QueueSchema } from "./schema-resources"; import { bindSimulatorResource, makeSimulatorJsClient } from "./util"; @@ -20,6 +24,7 @@ import { Duration, IInflightHost, Node, SDK_SOURCE_MODULE } from "../std"; export class Queue extends cloud.Queue implements ISimulatorResource { private readonly timeout: Duration; private readonly retentionPeriod: Duration; + private readonly policy: Policy; constructor(scope: Construct, id: string, props: cloud.QueueProps = {}) { super(scope, id, props); @@ -42,6 +47,8 @@ export class Queue extends cloud.Queue implements ISimulatorResource { "Retention period must be greater than or equal to timeout" ); } + + this.policy = new Policy(this, "Policy", { principal: this }); } /** @internal */ @@ -109,6 +116,12 @@ export class Queue extends cloud.Queue implements ISimulatorResource { name: "setConsumer()", }); + this.policy.addStatement(fn, cloud.FunctionInflightMethods.INVOKE); + this.policy.addStatement( + fn, + SimFunctionInflightMethods.HAS_AVAILABLE_WORKERS + ); + return fn; } @@ -127,7 +140,7 @@ export class Queue extends cloud.Queue implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/react-app.inflight.ts b/libs/wingsdk/src/target-sim/react-app.inflight.ts index c0fe6c181bf..ecbea6d853a 100644 --- a/libs/wingsdk/src/target-sim/react-app.inflight.ts +++ b/libs/wingsdk/src/target-sim/react-app.inflight.ts @@ -12,7 +12,7 @@ import { import { TraceType } from "../std"; export class ReactApp implements IReactAppClient, ISimulatorResourceInstance { - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; private readonly startCommand: string; private readonly path: string; private readonly environmentVariables: Record; @@ -21,8 +21,7 @@ export class ReactApp implements IReactAppClient, ISimulatorResourceInstance { private childProcess?: ChildProcess; private url: string; - constructor(props: ReactAppSchema["props"], context: ISimulatorContext) { - this.context = context; + constructor(props: ReactAppSchema["props"]) { this.path = props.path; this.startCommand = props.startCommand; this.environmentVariables = props.environmentVariables; @@ -31,7 +30,15 @@ export class ReactApp implements IReactAppClient, ISimulatorResourceInstance { this.url = props.url; } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; this.addTrace(`Executing start command: ${this.startCommand}`); writeFileSync( diff --git a/libs/wingsdk/src/target-sim/react-app.ts b/libs/wingsdk/src/target-sim/react-app.ts index 825428ec240..78c96c77f46 100644 --- a/libs/wingsdk/src/target-sim/react-app.ts +++ b/libs/wingsdk/src/target-sim/react-app.ts @@ -61,7 +61,7 @@ export class ReactApp extends ex.ReactApp implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/redis.inflight.ts b/libs/wingsdk/src/target-sim/redis.inflight.ts index b9d06b54cd8..7fc42111c57 100644 --- a/libs/wingsdk/src/target-sim/redis.inflight.ts +++ b/libs/wingsdk/src/target-sim/redis.inflight.ts @@ -15,14 +15,11 @@ export class Redis private connection?: IoRedis; private isCleanedUp = false; - public constructor( - private readonly props: RedisSchema["props"], - _context: ISimulatorContext - ) { + public constructor(private readonly props: RedisSchema["props"]) { super(); } - public async init(): Promise { + public async init(_context: ISimulatorContext): Promise { try { if (this.isCleanedUp) { return {}; diff --git a/libs/wingsdk/src/target-sim/redis.ts b/libs/wingsdk/src/target-sim/redis.ts index 908ee7f9ccb..a2d3c6fe886 100644 --- a/libs/wingsdk/src/target-sim/redis.ts +++ b/libs/wingsdk/src/target-sim/redis.ts @@ -50,7 +50,7 @@ export class Redis extends ex.Redis implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/resource.ts b/libs/wingsdk/src/target-sim/resource.ts index d3dfd03d7de..2c861f5dc76 100644 --- a/libs/wingsdk/src/target-sim/resource.ts +++ b/libs/wingsdk/src/target-sim/resource.ts @@ -1,9 +1,29 @@ import { BaseResourceSchema } from "../simulator/simulator"; -import { IResource } from "../std"; +import { IInflightHost, IResource } from "../std"; /** - * Interfaces shared by all polycon implementations (preflight classes) - * targeting the simulator. + * Interfaces shared by all preflight classes that host inflight code. + */ +export interface ISimulatorInflightHost extends IInflightHost { + /** + * Add a simulated permission to this inflight host. + * @param resource The resource to add + * @param op The action to add + */ + addPermission(resource: IResource, op: string): void; +} + +export function isSimulatorInflightHost( + obj: any +): obj is ISimulatorInflightHost { + return ( + typeof obj == "object" && + typeof (obj as ISimulatorInflightHost).addPermission === "function" + ); +} + +/** + * Interfaces shared by all preflight classes targeting the simulator. */ export interface ISimulatorResource extends IResource { /** diff --git a/libs/wingsdk/src/target-sim/schedule.inflight.ts b/libs/wingsdk/src/target-sim/schedule.inflight.ts index b2bade5f30d..5c44bebbacb 100644 --- a/libs/wingsdk/src/target-sim/schedule.inflight.ts +++ b/libs/wingsdk/src/target-sim/schedule.inflight.ts @@ -17,17 +17,23 @@ import { TraceType } from "../std"; export class Schedule implements IScheduleClient, ISimulatorResourceInstance, IEventPublisher { - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; private tasks = new Array(); private interval: CronExpression; private intervalTimeout?: NodeJS.Timeout; - constructor(props: ScheduleSchema["props"], context: ISimulatorContext) { - this.context = context; + constructor(props: ScheduleSchema["props"]) { this.interval = parseExpression(props.cronExpression, { utc: true }); this.scheduleFunction(); } + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + // Calculate the delay for the next execution private nextDelay(interval: CronExpression) { return interval.next().toDate().getTime() - Date.now(); @@ -41,7 +47,8 @@ export class Schedule }, this.nextDelay(this.interval)); } - public async init(): Promise { + public async init(context: ISimulatorContext): Promise { + this._context = context; return {}; } diff --git a/libs/wingsdk/src/target-sim/schedule.ts b/libs/wingsdk/src/target-sim/schedule.ts index 31289df757a..807f24b5c74 100644 --- a/libs/wingsdk/src/target-sim/schedule.ts +++ b/libs/wingsdk/src/target-sim/schedule.ts @@ -3,6 +3,7 @@ import { Construct } from "constructs"; import { App } from "./app"; import { EventMapping } from "./event-mapping"; import { Function } from "./function"; +import { Policy } from "./policy"; import { ISimulatorResource } from "./resource"; import { ScheduleSchema } from "./schema-resources"; import { @@ -22,12 +23,14 @@ import { IInflightHost, Node, SDK_SOURCE_MODULE } from "../std"; */ export class Schedule extends cloud.Schedule implements ISimulatorResource { private readonly cronExpression: string; + private readonly policy: Policy; constructor(scope: Construct, id: string, props: cloud.ScheduleProps = {}) { super(scope, id, props); const { rate, cron } = props; this.cronExpression = cron ?? convertDurationToCronExpression(rate!); + this.policy = new Policy(this, "Policy", { principal: this }); } public onTick( @@ -60,6 +63,7 @@ export class Schedule extends cloud.Schedule implements ISimulatorResource { target: fn, name: "onTick()", }); + this.policy.addStatement(fn, cloud.FunctionInflightMethods.INVOKE); return fn; } @@ -83,7 +87,7 @@ export class Schedule extends cloud.Schedule implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } } diff --git a/libs/wingsdk/src/target-sim/schema-resources.ts b/libs/wingsdk/src/target-sim/schema-resources.ts index 420843f531a..6da7f402ace 100644 --- a/libs/wingsdk/src/target-sim/schema-resources.ts +++ b/libs/wingsdk/src/target-sim/schema-resources.ts @@ -1,5 +1,7 @@ import { SIM_CONTAINER_FQN } from "./container"; import { EVENT_MAPPING_FQN } from "./event-mapping"; +import { POLICY_FQN } from "./policy"; +import { SERVICE_HELPER_FQN } from "./service"; import { STATE_FQN } from "./state"; import { API_FQN, @@ -26,8 +28,7 @@ import { } from "../simulator/simulator"; import { Json, TEST_RUNNER_FQN } from "../std"; -export type FunctionHandle = string; -export type PublisherHandle = string; +export type ResourceHandle = string; /** Schema for cloud.Api */ export interface ApiSchema extends BaseResourceSchema { @@ -95,8 +96,6 @@ export interface ServiceSchema extends BaseResourceSchema { readonly props: { /** The source code of the service */ readonly sourceCodeFile: string; - /** Whether the service should start when sim starts */ - readonly autoStart: boolean; /** A map of environment variables to run the function with. */ readonly environmentVariables: Record; }; @@ -105,6 +104,20 @@ export interface ServiceSchema extends BaseResourceSchema { /** Runtime attributes for cloud.Service */ export interface ServiceAttributes {} +/** Schema for sim.ServiceHelper */ +export interface ServiceHelperSchema extends BaseResourceSchema { + readonly type: typeof SERVICE_HELPER_FQN; + readonly props: { + /** The service. */ + readonly service: ResourceHandle; + /** Whether to auto-start the service */ + readonly autoStart: boolean; + }; +} + +/** Runtime attributes for sim.ServiceHelper */ +export interface ServiceHelperAttributes {} + /** Runtime attributes for cloud.Schedule */ export interface ScheduleAttributes {} @@ -120,7 +133,7 @@ export interface ScheduleSchema extends BaseResourceSchema { /** Schema for cloud.Queue.props.subscribers */ export interface ScheduleTask extends EventSubscription { /** Function that should be called. */ - readonly functionHandle: FunctionHandle; + readonly functionHandle: ResourceHandle; } export interface EventSubscription {} @@ -130,9 +143,9 @@ export interface EventMappingSchema extends BaseResourceSchema { readonly type: typeof EVENT_MAPPING_FQN; readonly props: { /** Function handle to call for subscriber */ - subscriber: FunctionHandle; + subscriber: ResourceHandle; /** Publisher handle of the event */ - publisher: PublisherHandle; + publisher: ResourceHandle; /** Additional properties of event subscription */ subscriptionProps: EventSubscription; }; @@ -147,7 +160,7 @@ export interface QueueAttributes {} /** Schema for cloud.Queue.props.subscribers */ export interface QueueSubscriber extends EventSubscription { /** Function that should be called. */ - readonly functionHandle: FunctionHandle; + readonly functionHandle: ResourceHandle; /** Maximum number of messages that will be batched together to the subscriber. */ readonly batchSize: number; } @@ -163,7 +176,7 @@ export interface TopicAttributes {} export interface TopicSubscriber extends EventSubscription { /** Function that should be called */ - readonly functionHandle: FunctionHandle; + readonly functionHandle: ResourceHandle; } /** Runtime attributes for cloud.Table */ @@ -213,7 +226,7 @@ export interface TestRunnerSchema extends BaseResourceSchema { readonly type: typeof TEST_RUNNER_FQN; readonly props: { /** A map from test functions to their handles. */ - readonly tests: Record; + readonly tests: Record; }; } @@ -288,7 +301,7 @@ export interface OnDeploySchema extends BaseResourceSchema { readonly type: typeof ON_DEPLOY_FQN; readonly props: { /** The function to run on deploy. */ - readonly functionHandle: FunctionHandle; + readonly functionHandle: ResourceHandle; }; } @@ -335,6 +348,9 @@ export interface EndpointSchema extends BaseResourceSchema { readonly attrs: EndpointAttributes & BaseResourceAttributes; } +/** Runtime attributes for sim.Policy */ +export interface PolicyAttributes {} + /** Schema for sim.Container */ export interface ContainerSchema extends BaseResourceSchema { readonly type: typeof SIM_CONTAINER_FQN; @@ -351,3 +367,22 @@ export interface ContainerSchema extends BaseResourceSchema { /** Runtime attributes for sim.Container */ export interface ContainerAttributes {} + +/** Schema for sim.Policy */ +export interface PolicySchema extends BaseResourceSchema { + readonly type: typeof POLICY_FQN; + readonly props: PolicySchemaProps; + readonly attrs: PolicyAttributes & BaseResourceAttributes; +} + +export interface PolicySchemaProps { + /** The resource which the policy is attached to. */ + readonly principal: ResourceHandle; + /** The statements in the policy. */ + readonly statements: PolicyStatement[]; +} + +export interface PolicyStatement { + readonly operation: string; + readonly resourceHandle: ResourceHandle; +} diff --git a/libs/wingsdk/src/target-sim/secret.inflight.ts b/libs/wingsdk/src/target-sim/secret.inflight.ts index 02791e12cf6..d178a7bee69 100644 --- a/libs/wingsdk/src/target-sim/secret.inflight.ts +++ b/libs/wingsdk/src/target-sim/secret.inflight.ts @@ -11,13 +11,11 @@ import { import { Json, TraceType } from "../std"; export class Secret implements ISecretClient, ISimulatorResourceInstance { - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; private readonly secretsFile: string; private readonly name: string; - constructor(props: SecretSchema["props"], context: ISimulatorContext) { - this.context = context; - + constructor(props: SecretSchema["props"]) { this.secretsFile = path.join(os.homedir(), ".wing", "secrets.json"); if (!fs.existsSync(this.secretsFile)) { throw new Error( @@ -28,7 +26,15 @@ export class Secret implements ISecretClient, ISimulatorResourceInstance { this.name = props.name; } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; return {}; } diff --git a/libs/wingsdk/src/target-sim/secret.ts b/libs/wingsdk/src/target-sim/secret.ts index aeee0c16a7f..97b2a366bfd 100644 --- a/libs/wingsdk/src/target-sim/secret.ts +++ b/libs/wingsdk/src/target-sim/secret.ts @@ -23,7 +23,7 @@ export class Secret extends cloud.Secret implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/service.inflight.ts b/libs/wingsdk/src/target-sim/service.inflight.ts index fc705431671..4c6ced2f889 100644 --- a/libs/wingsdk/src/target-sim/service.inflight.ts +++ b/libs/wingsdk/src/target-sim/service.inflight.ts @@ -1,5 +1,9 @@ import { resolve } from "path"; -import { ServiceAttributes, ServiceSchema } from "./schema-resources"; +import { + ServiceAttributes, + ServiceHelperSchema, + ServiceSchema, +} from "./schema-resources"; import { IServiceClient, SERVICE_FQN } from "../cloud"; import { Bundle } from "../shared/bundling"; import { Sandbox } from "../shared/sandbox"; @@ -11,38 +15,45 @@ import { import { TraceType } from "../std"; export class Service implements IServiceClient, ISimulatorResourceInstance { - private readonly context: ISimulatorContext; - private readonly originalFile: string; - private readonly autoStart: boolean; + private _context: ISimulatorContext | undefined; + private readonly sourceCodeFile: string; + private resolvedSourceCodeFile!: string; private sandbox: Sandbox | undefined; private bundle: Bundle | undefined; - private createBundlePromise: Promise; private running: boolean = false; private environmentVariables: Record; + private createBundlePromise!: Promise; - constructor(props: ServiceSchema["props"], context: ISimulatorContext) { - this.context = context; - this.originalFile = resolve(context.simdir, props.sourceCodeFile); - this.autoStart = props.autoStart; + constructor(props: ServiceSchema["props"]) { + this.sourceCodeFile = props.sourceCodeFile; this.environmentVariables = props.environmentVariables ?? {}; + } - this.createBundlePromise = this.createBundle(); + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; } private async createBundle(): Promise { - this.bundle = await Sandbox.createBundle(this.originalFile, (msg) => { - this.addTrace(msg); - }); + this.bundle = await Sandbox.createBundle( + this.resolvedSourceCodeFile, + (msg) => { + this.addTrace(msg); + } + ); } - public async init(): Promise { - if (this.autoStart) { - await this.start(); - } + public async init(context: ISimulatorContext): Promise { + this._context = context; + this.resolvedSourceCodeFile = resolve(context.simdir, this.sourceCodeFile); + this.createBundlePromise = this.createBundle(); return {}; } public async cleanup(): Promise { + await this.createBundlePromise; await this.stop(); } @@ -71,6 +82,7 @@ export class Service implements IServiceClient, ISimulatorResourceInstance { env: { ...this.environmentVariables, WING_SIMULATOR_URL: this.context.serverUrl, + WING_SIMULATOR_CALLER: this.context.resourceHandle, }, log: (internal, _level, message) => { this.addTrace(message, internal); @@ -97,7 +109,7 @@ export class Service implements IServiceClient, ISimulatorResourceInstance { await this.sandbox.call("stop"); await this.sandbox.cleanup(); } catch (e: any) { - this.addTrace(`Failed to stop service: ${e.message}`); + this.addTrace(`Failed to stop service: ${e.message} ${e.stack}`); } } @@ -115,3 +127,41 @@ export class Service implements IServiceClient, ISimulatorResourceInstance { }); } } + +export class ServiceHelper implements ISimulatorResourceInstance { + private readonly serviceHandle: string; + private readonly autoStart: boolean; + private _context: ISimulatorContext | undefined; + + public constructor(props: ServiceHelperSchema["props"]) { + this.serviceHandle = props.service; + this.autoStart = props.autoStart; + } + + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; + if (this.autoStart) { + const service = context.getClient(this.serviceHandle, true) as Service; + await service.start(); + } + return {}; + } + + public async cleanup(): Promise { + const service = this.context.getClient(this.serviceHandle, true) as Service; + await service.stop(); + } + + public async save(): Promise {} + + public async plan(): Promise { + return UpdatePlan.AUTO; + } +} diff --git a/libs/wingsdk/src/target-sim/service.ts b/libs/wingsdk/src/target-sim/service.ts index d2c21f26a2a..1269ab419f8 100644 --- a/libs/wingsdk/src/target-sim/service.ts +++ b/libs/wingsdk/src/target-sim/service.ts @@ -1,15 +1,22 @@ import { relative } from "path"; import { Construct } from "constructs"; -import { ISimulatorResource } from "./resource"; -import { ServiceSchema } from "./schema-resources"; +import { Policy } from "./policy"; +import { ISimulatorInflightHost, ISimulatorResource } from "./resource"; +import { ServiceHelperSchema, ServiceSchema } from "./schema-resources"; +import { simulatorHandleToken } from "./tokens"; import { bindSimulatorResource, makeSimulatorJsClient } from "./util"; import * as cloud from "../cloud"; +import { fqnForType } from "../constants"; import { App } from "../core"; import { BaseResourceSchema } from "../simulator"; -import { IInflightHost } from "../std"; +import { IInflightHost, IResource, Resource, Node } from "../std"; -export class Service extends cloud.Service implements ISimulatorResource { - private readonly autoStart: boolean; +export class Service + extends cloud.Service + implements ISimulatorResource, ISimulatorInflightHost +{ + public readonly policy: Policy; + public _liftMap = undefined; constructor( scope: Construct, @@ -18,7 +25,18 @@ export class Service extends cloud.Service implements ISimulatorResource { props: cloud.ServiceProps = {} ) { super(scope, id, handler, props); - this.autoStart = props.autoStart ?? true; + this.policy = new Policy(this, "Policy", { principal: this }); + + const helper = new ServiceHelper(this, "Helper", { + service: this, + autoStart: props.autoStart ?? true, + }); + helper.node.addDependency(this); + helper.node.addDependency(this.policy); + } + + public addPermission(resource: IResource, op: string): void { + this.policy.addStatement(resource, op); } public toSimulator(): BaseResourceSchema { @@ -29,7 +47,6 @@ export class Service extends cloud.Service implements ISimulatorResource { props: { environmentVariables: this.env, sourceCodeFile: relative(App.of(this).outdir, this.entrypoint), - autoStart: this.autoStart, }, attrs: {} as any, }; @@ -46,7 +63,7 @@ export class Service extends cloud.Service implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } @@ -54,3 +71,51 @@ export class Service extends cloud.Service implements ISimulatorResource { return makeSimulatorJsClient(__filename, this); } } + +/** @internal */ +export const SERVICE_HELPER_FQN = fqnForType("sim.ServiceHelper"); + +/** @internal */ +export interface ServiceHelperProps { + readonly service: Service; + readonly autoStart: boolean; +} + +/** + * This is a helper resource that automatically starts the service after the + * service is created in the simulator and shuts it down when the simulator + * stops. + * + * Suppose a service puts an object in a bucket when it starts. The policy + * (sim.Policy) that grants the service bucket permissions only takes effect + * after the service is created. Because of this, the service needs to be + * started after both the service and the policy are created. Vice versa, the + * service needs to be stopped before the policy is deleted. + * + * @internal + */ +export class ServiceHelper extends Resource implements ISimulatorResource { + private readonly service: Service; + private readonly autoStart: boolean; + + constructor(scope: Construct, id: string, props: ServiceHelperProps) { + super(scope, id); + this.service = props.service; + this.autoStart = props.autoStart; + Node.of(this).hidden = true; + } + + public toSimulator(): BaseResourceSchema { + const schema: ServiceHelperSchema = { + type: SERVICE_HELPER_FQN, + path: this.node.path, + addr: this.node.addr, + props: { + service: simulatorHandleToken(this.service), + autoStart: this.autoStart, + }, + attrs: {} as any, + }; + return schema; + } +} diff --git a/libs/wingsdk/src/target-sim/state.inflight.ts b/libs/wingsdk/src/target-sim/state.inflight.ts index ceb4f946acd..0472e417740 100644 --- a/libs/wingsdk/src/target-sim/state.inflight.ts +++ b/libs/wingsdk/src/target-sim/state.inflight.ts @@ -8,11 +8,18 @@ import { import { Json } from "../std"; export class State implements IStateClient, ISimulatorResourceInstance { - constructor( - _props: StateSchema["props"], - private readonly context: ISimulatorContext - ) {} - public async init(): Promise> { + private _context: ISimulatorContext | undefined; + constructor(_props: StateSchema["props"]) {} + + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise> { + this._context = context; return {}; } diff --git a/libs/wingsdk/src/target-sim/state.ts b/libs/wingsdk/src/target-sim/state.ts index 7f3ed33cc6e..3320bc50903 100644 --- a/libs/wingsdk/src/target-sim/state.ts +++ b/libs/wingsdk/src/target-sim/state.ts @@ -53,7 +53,7 @@ export class State extends Resource implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/table.inflight.ts b/libs/wingsdk/src/target-sim/table.inflight.ts index 5e543fc1e7f..ed48673cf11 100644 --- a/libs/wingsdk/src/target-sim/table.inflight.ts +++ b/libs/wingsdk/src/target-sim/table.inflight.ts @@ -13,19 +13,26 @@ export class Table implements ITableClient, ISimulatorResourceInstance { private columns: { [key: string]: ColumnType }; private primaryKey: string; private table: Map; - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; private readonly initialRows: Record; - public constructor(props: TableSchema["props"], context: ISimulatorContext) { + public constructor(props: TableSchema["props"]) { this.name = props.name; this.columns = props.columns; this.primaryKey = props.primaryKey; this.table = new Map(); - this.context = context; this.initialRows = props.initialRows ?? {}; } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; for (const [key, row] of Object.entries(this.initialRows)) { await this.context.withTrace({ message: `Adding initial row (key=${key}).`, diff --git a/libs/wingsdk/src/target-sim/table.ts b/libs/wingsdk/src/target-sim/table.ts index 6663052eeed..58ed24b5f64 100644 --- a/libs/wingsdk/src/target-sim/table.ts +++ b/libs/wingsdk/src/target-sim/table.ts @@ -51,7 +51,7 @@ export class Table extends ex.Table implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/test-runner.inflight.ts b/libs/wingsdk/src/target-sim/test-runner.inflight.ts index f17fd067c60..0a4447689b3 100644 --- a/libs/wingsdk/src/target-sim/test-runner.inflight.ts +++ b/libs/wingsdk/src/target-sim/test-runner.inflight.ts @@ -12,14 +12,21 @@ export class TestRunner { // A map from test paths to their corresponding function handles. private readonly tests: Map; - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; - constructor(props: TestRunnerSchema["props"], context: ISimulatorContext) { + constructor(props: TestRunnerSchema["props"]) { this.tests = new Map(Object.entries(props.tests)); - this.context = context; } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; return {}; } @@ -42,7 +49,10 @@ export class TestRunner if (!functionHandle) { throw new Error(`No test found at path "${path}"`); } - const fnClient = this.context.getClient(functionHandle) as IFunctionClient; + const fnClient = this.context.getClient( + functionHandle, + true + ) as IFunctionClient; let pass = false; let error: string | undefined; const previousTraces = this.context.listTraces().length; diff --git a/libs/wingsdk/src/target-sim/test-runner.ts b/libs/wingsdk/src/target-sim/test-runner.ts index edab23072ea..f2ebda594e7 100644 --- a/libs/wingsdk/src/target-sim/test-runner.ts +++ b/libs/wingsdk/src/target-sim/test-runner.ts @@ -32,7 +32,7 @@ export class TestRunner extends std.TestRunner implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource("test-runner", this, host); + bindSimulatorResource("test-runner", this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/topic.inflight.ts b/libs/wingsdk/src/target-sim/topic.inflight.ts index 4efffd0e1a0..cd532b343ef 100644 --- a/libs/wingsdk/src/target-sim/topic.inflight.ts +++ b/libs/wingsdk/src/target-sim/topic.inflight.ts @@ -4,7 +4,7 @@ import { TopicSchema, TopicSubscriber, EventSubscription, - FunctionHandle, + ResourceHandle, } from "./schema-resources"; import { IFunctionClient, ITopicClient, TOPIC_FQN } from "../cloud"; import { @@ -18,14 +18,19 @@ export class Topic implements ITopicClient, ISimulatorResourceInstance, IEventPublisher { private readonly subscribers = new Array(); - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; - constructor(props: TopicSchema["props"], context: ISimulatorContext) { - this.context = context; - props; + constructor(_props: TopicSchema["props"]) {} + + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; } - public async init(): Promise { + public async init(context: ISimulatorContext): Promise { + this._context = context; return {}; } @@ -57,7 +62,7 @@ export class Topic } public async addEventSubscription( - subscriber: FunctionHandle, + subscriber: ResourceHandle, subscriptionProps: EventSubscription ): Promise { let s = { diff --git a/libs/wingsdk/src/target-sim/topic.ts b/libs/wingsdk/src/target-sim/topic.ts index a6a888e6470..df9a4863112 100644 --- a/libs/wingsdk/src/target-sim/topic.ts +++ b/libs/wingsdk/src/target-sim/topic.ts @@ -3,6 +3,7 @@ import { Construct } from "constructs"; import { App } from "./app"; import { EventMapping } from "./event-mapping"; import { Function } from "./function"; +import { Policy } from "./policy"; import { ISimulatorResource } from "./resource"; import { TopicSchema } from "./schema-resources"; import { bindSimulatorResource, makeSimulatorJsClient } from "./util"; @@ -20,8 +21,10 @@ const QUEUE_PUSH_METHOD = "push"; * @inflight `@winglang/sdk.cloud.ITopicClient` */ export class Topic extends cloud.Topic implements ISimulatorResource { + public readonly policy: Policy; constructor(scope: Construct, id: string, props: cloud.TopicProps = {}) { super(scope, id, props); + this.policy = new Policy(this, "Policy", { principal: this }); } public onMessage( @@ -55,6 +58,8 @@ export class Topic extends cloud.Topic implements ISimulatorResource { name: "onMessage()", }); + this.policy.addStatement(fn, cloud.FunctionInflightMethods.INVOKE_ASYNC); + return fn; } @@ -93,10 +98,12 @@ export class Topic extends cloud.Topic implements ISimulatorResource { target: fn, name: "subscribeQueue()", }); + + this.policy.addStatement(fn, cloud.FunctionInflightMethods.INVOKE_ASYNC); } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/target-sim/util.ts b/libs/wingsdk/src/target-sim/util.ts index 17074dec81b..e31dfce9f47 100644 --- a/libs/wingsdk/src/target-sim/util.ts +++ b/libs/wingsdk/src/target-sim/util.ts @@ -2,6 +2,7 @@ import { access, constants } from "fs"; import { basename } from "path"; import { promisify } from "util"; import { IConstruct } from "constructs"; +import { isSimulatorInflightHost } from "./resource"; import { simulatorHandleToken } from "./tokens"; import { Duration, IInflightHost, Resource } from "../std"; @@ -31,13 +32,23 @@ function makeEnvVarName(type: string, resource: IConstruct): string { export function bindSimulatorResource( filename: string, resource: Resource, - host: IInflightHost + host: IInflightHost, + ops: string[] ) { + // Check if host implements ISimulatorInflightHost + if (!isSimulatorInflightHost(host)) { + throw new Error( + "Host resource must implement sim.ISimulatorInflightHost to bind simulator resources" + ); + } const type = basename(filename).split(".")[0]; const env = makeEnvVarName(type, resource); const handle = simulatorHandleToken(resource); host.addEnvironment(env, handle); host.node.addDependency(resource); + for (const op of ops) { + host.addPermission(resource, op); + } } export function makeSimulatorJsClient(filename: string, resource: Resource) { @@ -52,7 +63,11 @@ export function makeSimulatorJsClient(filename: string, resource: Resource) { if (!simulatorUrl) { throw new Error("Missing environment variable: WING_SIMULATOR_URL"); } - return require("@winglang/sdk/lib/simulator/client").makeSimulatorClient(simulatorUrl, handle); + const caller = process.env.WING_SIMULATOR_CALLER; + if (!caller) { + throw new Error("Missing environment variable: WING_SIMULATOR_CALLER"); + } + return require("@winglang/sdk/lib/simulator/client").makeSimulatorClient(simulatorUrl, handle, caller); })()`; } diff --git a/libs/wingsdk/src/target-sim/website.inflight.ts b/libs/wingsdk/src/target-sim/website.inflight.ts index aa11fe4eeff..f25472134e6 100644 --- a/libs/wingsdk/src/target-sim/website.inflight.ts +++ b/libs/wingsdk/src/target-sim/website.inflight.ts @@ -14,14 +14,12 @@ import { TraceType } from "../std"; const LOCALHOST_ADDRESS = "127.0.0.1"; export class Website implements IWebsiteClient, ISimulatorResourceInstance { - private readonly context: ISimulatorContext; + private _context: ISimulatorContext | undefined; private readonly app: express.Application; private server?: Server; private url?: string; - constructor(props: WebsiteSchema["props"], context: ISimulatorContext) { - this.context = context; - + constructor(props: WebsiteSchema["props"]) { // Set up an express server that handles the routes. this.app = express(); @@ -48,7 +46,15 @@ export class Website implements IWebsiteClient, ISimulatorResourceInstance { } } - public async init(): Promise { + private get context(): ISimulatorContext { + if (!this._context) { + throw new Error("Cannot access context during class construction"); + } + return this._context; + } + + public async init(context: ISimulatorContext): Promise { + this._context = context; // `server.address()` returns `null` until the server is listening // on a port. We use a promise to wait for the server to start // listening before returning the URL. diff --git a/libs/wingsdk/src/target-sim/website.ts b/libs/wingsdk/src/target-sim/website.ts index 8e90e25e231..4e4ca6accfb 100644 --- a/libs/wingsdk/src/target-sim/website.ts +++ b/libs/wingsdk/src/target-sim/website.ts @@ -63,7 +63,7 @@ export class Website extends cloud.Website implements ISimulatorResource { } public onLift(host: IInflightHost, ops: string[]): void { - bindSimulatorResource(__filename, this, host); + bindSimulatorResource(__filename, this, host, ops); super.onLift(host, ops); } diff --git a/libs/wingsdk/src/util/enhanced-error.ts b/libs/wingsdk/src/util/enhanced-error.ts index e3dbe7a37ca..ba8a541e4a5 100644 --- a/libs/wingsdk/src/util/enhanced-error.ts +++ b/libs/wingsdk/src/util/enhanced-error.ts @@ -79,8 +79,7 @@ export async function prettyPrintError( ) // special: remove the handler wrapper (See `cloud.Function` entrypoint for where this comes from) .filter( - (item) => - !normalPath(item.file).match(/\.wing\/handler_\w+(\.sandbox)?\.js$/) + (item) => !normalPath(item.file).match(/\.wing\/\w+(\.sandbox)?\.js$/) ) .withSourcesAsync(); diff --git a/libs/wingsdk/test/core/__snapshots__/connections.test.ts.snap b/libs/wingsdk/test/core/__snapshots__/connections.test.ts.snap index 94c737a6e30..df0506ae6ec 100644 --- a/libs/wingsdk/test/core/__snapshots__/connections.test.ts.snap +++ b/libs/wingsdk/test/core/__snapshots__/connections.test.ts.snap @@ -42,6 +42,16 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Bucket", }, + { + "addr": "c8b5ba55132964ee19331fb9f46241560e67fed76b", + "attrs": {}, + "path": "root/my_bucket/Policy", + "props": { + "principal": "\${wsim#root/my_bucket#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c85c4e0e66bf385ab6b159bab34fb32dd81aad0a1d", "attrs": {}, @@ -55,6 +65,16 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c8d421ed6ca2ddf857d835791bcde9240c8682a8d9", + "attrs": {}, + "path": "root/my_function/Policy", + "props": { + "principal": "\${wsim#root/my_function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -130,6 +150,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -144,6 +172,21 @@ return class Handler { "tree": { "children": { "my_bucket": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_bucket/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -156,6 +199,21 @@ return class Handler { "path": "root/my_bucket", }, "my_function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", diff --git a/libs/wingsdk/test/simulator/cleanup.test.ts b/libs/wingsdk/test/simulator/cleanup.test.ts index 9a62a311927..a85bcf9efd4 100644 --- a/libs/wingsdk/test/simulator/cleanup.test.ts +++ b/libs/wingsdk/test/simulator/cleanup.test.ts @@ -55,13 +55,12 @@ test("simulator cleanup", async () => { stdio: ["pipe", "pipe", "pipe"], }); - // Uncomment the following lines to see the output of the child process - // child.stdout?.on("data", (data) => { - // console.error(data.toString()); - // }); - // child.stderr?.on("data", (data) => { - // console.error(data.toString()); - // }); + child.stdout?.on("data", (data) => { + console.error(data.toString()); + }); + child.stderr?.on("data", (data) => { + console.error(data.toString()); + }); let stopped = false; @@ -72,6 +71,12 @@ test("simulator cleanup", async () => { resolve(undefined); } }); + child.stderr?.on("data", (data) => { + if (data.toString().includes("stopped!")) { + stopped = true; + resolve(undefined); + } + }); }); // Wait for the "Simulator started" message, then kill the child process @@ -82,6 +87,12 @@ test("simulator cleanup", async () => { resolve(undefined); } }); + child.stderr?.on("data", (data) => { + if (data.toString().includes("Simulator started")) { + child.kill("SIGTERM"); + resolve(undefined); + } + }); }); // Wait for the "stopped!" message from cloud.Service (running in a grandchild process) diff --git a/libs/wingsdk/test/simulator/on-trace.test.ts b/libs/wingsdk/test/simulator/on-trace.test.ts index ffab782d4ef..cee2e130f88 100644 --- a/libs/wingsdk/test/simulator/on-trace.test.ts +++ b/libs/wingsdk/test/simulator/on-trace.test.ts @@ -27,5 +27,5 @@ test("onTrace", async () => { await s.stop(); // THEN - expect(numTraces).toEqual(3); // create resources, put operation, delete resources + expect(numTraces).toBeGreaterThanOrEqual(3); // create resources, put operation, delete resources }); diff --git a/libs/wingsdk/test/simulator/simulator.test.ts b/libs/wingsdk/test/simulator/simulator.test.ts index 24015bc5ccd..634420c80bb 100644 --- a/libs/wingsdk/test/simulator/simulator.test.ts +++ b/libs/wingsdk/test/simulator/simulator.test.ts @@ -214,9 +214,15 @@ describe("in-place updates", () => { new Bucket(app, "Bucket1"); const sim = await app.startSimulator(stateDir); - expect(sim.listResources()).toEqual(["root/Bucket1"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + ]); - expect(simTraces(sim)).toStrictEqual(["root/Bucket1 started"]); + expect(simTraces(sim)).toStrictEqual([ + "root/Bucket1 started", + "root/Bucket1/Policy started", + ]); const app2 = new SimApp(); new Bucket(app2, "Bucket1"); @@ -232,10 +238,14 @@ describe("in-place updates", () => { expect(simTraces(sim)).toStrictEqual([ "root/Bucket1 started", + "root/Bucket1/Policy started", "Update: 0 added, 0 updated, 0 deleted", ]); - expect(sim.listResources()).toEqual(["root/Bucket1"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + ]); await sim.stop(); }); @@ -246,8 +256,14 @@ describe("in-place updates", () => { new Bucket(app, "Bucket1"); const sim = await app.startSimulator(stateDir); - expect(sim.listResources()).toEqual(["root/Bucket1"]); - expect(simTraces(sim)).toStrictEqual(["root/Bucket1 started"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + ]); + expect(simTraces(sim)).toStrictEqual([ + "root/Bucket1 started", + "root/Bucket1/Policy started", + ]); const app2 = new SimApp(); new Bucket(app2, "Bucket1"); @@ -256,16 +272,23 @@ describe("in-place updates", () => { const app2Dir = app2.synth(); await sim.update(app2Dir); expect(updateTrace(sim)).toStrictEqual({ - added: ["root/Bucket2"], + added: ["root/Bucket2", "root/Bucket2/Policy"], deleted: [], updated: [], }); - expect(sim.listResources()).toEqual(["root/Bucket1", "root/Bucket2"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + "root/Bucket2", + "root/Bucket2/Policy", + ]); expect(simTraces(sim)).toStrictEqual([ "root/Bucket1 started", - "Update: 1 added, 0 updated, 0 deleted", + "root/Bucket1/Policy started", + "Update: 2 added, 0 updated, 0 deleted", "root/Bucket2 started", + "root/Bucket2/Policy started", ]); await sim.stop(); @@ -278,10 +301,17 @@ describe("in-place updates", () => { new Bucket(app, "Bucket1"); new Bucket(app, "Bucket2"); const sim = await app.startSimulator(stateDir); - expect(sim.listResources()).toEqual(["root/Bucket1", "root/Bucket2"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + "root/Bucket2", + "root/Bucket2/Policy", + ]); expect(simTraces(sim)).toStrictEqual([ "root/Bucket1 started", + "root/Bucket1/Policy started", "root/Bucket2 started", + "root/Bucket2/Policy started", ]); const app2 = new SimApp(); @@ -291,16 +321,22 @@ describe("in-place updates", () => { await sim.update(app2Dir); expect(updateTrace(sim)).toStrictEqual({ added: [], - deleted: ["root/Bucket2"], + deleted: ["root/Bucket2", "root/Bucket2/Policy"], updated: [], }); - expect(sim.listResources()).toEqual(["root/Bucket1"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + ]); expect(simTraces(sim)).toStrictEqual([ "root/Bucket1 started", + "root/Bucket1/Policy started", "root/Bucket2 started", - "Update: 0 added, 0 updated, 1 deleted", + "root/Bucket2/Policy started", + "Update: 0 added, 0 updated, 2 deleted", + "root/Bucket2/Policy stopped", "root/Bucket2 stopped", ]); @@ -313,9 +349,15 @@ describe("in-place updates", () => { const app = new SimApp(); new Bucket(app, "Bucket1"); const sim = await app.startSimulator(stateDir); - expect(sim.listResources()).toEqual(["root/Bucket1"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + ]); expect(sim.getResourceConfig("root/Bucket1").props.public).toBeFalsy(); - expect(simTraces(sim)).toStrictEqual(["root/Bucket1 started"]); + expect(simTraces(sim)).toStrictEqual([ + "root/Bucket1 started", + "root/Bucket1/Policy started", + ]); const app2 = new SimApp(); new Bucket(app2, "Bucket1", { public: true }); @@ -328,13 +370,19 @@ describe("in-place updates", () => { updated: ["root/Bucket1"], }); - expect(sim.listResources()).toEqual(["root/Bucket1"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + ]); expect(simTraces(sim)).toStrictEqual([ "root/Bucket1 started", + "root/Bucket1/Policy started", "Update: 0 added, 1 updated, 0 deleted", + "root/Bucket1/Policy stopped", "root/Bucket1 stopped", "root/Bucket1 started", + "root/Bucket1/Policy started", ]); expect(sim.getResourceConfig("root/Bucket1").props.public).toBeTruthy(); @@ -350,9 +398,15 @@ describe("in-place updates", () => { const sim = await app.startSimulator(stateDir); - expect(simTraces(sim)).toStrictEqual(["root/Bucket1 started"]); + expect(simTraces(sim)).toStrictEqual([ + "root/Bucket1 started", + "root/Bucket1/Policy started", + ]); - expect(sim.listResources()).toEqual(["root/Bucket1"]); + expect(sim.listResources()).toEqual([ + "root/Bucket1", + "root/Bucket1/Policy", + ]); expect(sim.getResourceConfig("root/Bucket1").props.public).toBeFalsy(); const app2 = new SimApp(); @@ -369,26 +423,40 @@ describe("in-place updates", () => { await sim.update(app2Dir); expect(updateTrace(sim)).toStrictEqual({ - added: ["root/Api", "root/Api/Endpoint", "root/Function"], + added: [ + "root/Api", + "root/Api/Endpoint", + "root/Api/Policy", + "root/Function", + "root/Function/Policy", + ], deleted: [], updated: ["root/Bucket1"], }); expect(simTraces(sim)).toStrictEqual([ "root/Bucket1 started", - "Update: 3 added, 1 updated, 0 deleted", + "root/Bucket1/Policy started", + "Update: 5 added, 1 updated, 0 deleted", + "root/Bucket1/Policy stopped", "root/Bucket1 stopped", "root/Api started", "root/Bucket1 started", + "root/Bucket1/Policy started", "root/Api/Endpoint started", + "root/Api/Policy started", "root/Function started", + "root/Function/Policy started", ]); expect(sim.listResources()).toEqual([ "root/Api", "root/Api/Endpoint", + "root/Api/Policy", "root/Bucket1", + "root/Bucket1/Policy", "root/Function", + "root/Function/Policy", ]); const bucketClient = sim.getResource("root/Bucket1") as IBucketClient; @@ -443,15 +511,12 @@ describe("in-place updates", () => { const stateDir = mkdtemp(); const sim = await app.startSimulator(stateDir); - const urlBeforeUpdate = await sim - .getResource("root/Bucket1") - .get("url.txt"); - expect(urlBeforeUpdate.startsWith("http://127.0.0")).toBeTruthy(); - expect(simTraces(sim)).toEqual([ "root/Api1 started", "root/Api1/Endpoint started", + "root/Api1/Policy started", "root/Bucket1 started", + "root/Bucket1/Policy started", ]); // now lets change some configuration of Api1. we expect the bucket to be replaced as well @@ -461,35 +526,35 @@ describe("in-place updates", () => { const myBucket2 = new Bucket(app2, "Bucket1"); myBucket2.addObject("url.txt", myApi2.url); - // clear the state directory - fs.rmdirSync(stateDir, { recursive: true }); - const app2Dir = app2.synth(); await sim.update(app2Dir); expect(updateTrace(sim)).toStrictEqual({ added: [], deleted: [], - updated: ["root/Api1"], + updated: ["root/Api1"], // TODO: shouldn't Bucket also be listed here? }); expect(simTraces(sim)).toEqual([ "root/Api1 started", "root/Api1/Endpoint started", + "root/Api1/Policy started", "root/Bucket1 started", + "root/Bucket1/Policy started", "Update: 0 added, 1 updated, 0 deleted", "root/Api1/Endpoint stopped", + "root/Api1/Policy stopped", + "root/Bucket1/Policy stopped", "root/Bucket1 stopped", "root/Api1 stopped", "root/Api1 started", "root/Api1/Endpoint started", + "root/Api1/Policy started", "root/Bucket1 started", + "root/Bucket1/Policy started", ]); - const urlAfterUpdate = await ( - sim.getResource("root/Bucket1") as IBucketClient - ).get("url.txt"); - expect(urlAfterUpdate).not.toEqual(urlBeforeUpdate); + await sim.stop(); }); test("token value is changed across an update", async () => { @@ -551,15 +616,24 @@ describe("in-place updates", () => { expect(simTraces(sim)).toEqual([ "root/State started", - "root/State.my_value = bang", "root/Service started", + "root/Service/Policy started", + "root/State.my_value = bang", + "root/Service/Helper started", "root/Function started", + "root/Function/Policy started", "Update: 0 added, 2 updated, 0 deleted", + "root/Service/Helper stopped", + "root/Service/Policy stopped", "root/Service stopped", + "root/Function/Policy stopped", "root/Function stopped", - "root/State.my_value = bing", "root/Service started", + "root/Service/Policy started", + "root/State.my_value = bing", + "root/Service/Helper started", "root/Function started", + "root/Function/Policy started", ]); }); @@ -584,15 +658,21 @@ describe("in-place updates", () => { await sim.update(app2Dir); expect(simTraces(sim)).toEqual([ - "root/OnDeploy/Function started", "root/Bucket1 started", + "root/Bucket1/Policy started", + "root/OnDeploy/Function started", + "root/OnDeploy/Function/Policy started", "root/OnDeploy started", - "Update: 0 added, 2 updated, 0 deleted", + "Update: 0 added, 3 updated, 0 deleted", "root/OnDeploy stopped", + "root/OnDeploy/Function/Policy stopped", "root/OnDeploy/Function stopped", + "root/Bucket1/Policy stopped", "root/Bucket1 stopped", - "root/OnDeploy/Function started", "root/Bucket1 started", + "root/Bucket1/Policy started", + "root/OnDeploy/Function started", + "root/OnDeploy/Function/Policy started", "root/OnDeploy started", ]); }); @@ -612,9 +692,12 @@ describe("in-place updates", () => { expect(simTraces(sim)).toEqual([ "root/Function started", + "root/Function/Policy started", "Update: 0 added, 1 updated, 0 deleted", + "root/Function/Policy stopped", "root/Function stopped", "root/Function started", + "root/Function/Policy started", ]); }); @@ -633,9 +716,42 @@ describe("in-place updates", () => { expect(simTraces(sim)).toEqual([ "root/Service started", + "root/Service/Policy started", + "root/Service/Helper started", "Update: 0 added, 1 updated, 0 deleted", + "root/Service/Helper stopped", + "root/Service/Policy stopped", "root/Service stopped", "root/Service started", + "root/Service/Policy started", + "root/Service/Helper started", + ]); + }); + + test("cloud.OnDeploy is always replaced", async () => { + const app = new SimApp(); + const handler = Testing.makeHandler(`async handle() {}`); + new OnDeploy(app, "OnDeploy", handler); + + const sim = await app.startSimulator(); + + const app2 = new SimApp(); + new OnDeploy(app2, "OnDeploy", handler); + + const app2Dir = app2.synth(); + await sim.update(app2Dir); + + expect(simTraces(sim)).toEqual([ + "root/OnDeploy/Function started", + "root/OnDeploy/Function/Policy started", + "root/OnDeploy started", + "Update: 0 added, 2 updated, 0 deleted", + "root/OnDeploy stopped", + "root/OnDeploy/Function/Policy stopped", + "root/OnDeploy/Function stopped", + "root/OnDeploy/Function started", + "root/OnDeploy/Function/Policy started", + "root/OnDeploy started", ]); }); @@ -671,8 +787,12 @@ describe("in-place updates", () => { "root/Api started", "root/Api/Endpoint started", "root/Api/OnRequestHandler0 started", + "root/Api/Policy started", + "root/Api/OnRequestHandler0/Policy started", "root/Api/ApiEventMapping0 started", "Update: 0 added, 3 updated, 0 deleted", + "root/Api/Policy stopped", + "root/Api/OnRequestHandler0/Policy stopped", "root/Api/ApiEventMapping0 stopped", "root/Api/OnRequestHandler0 stopped", "root/Api/Endpoint stopped", @@ -680,6 +800,8 @@ describe("in-place updates", () => { "root/Api started", "root/Api/Endpoint started", "root/Api/OnRequestHandler0 started", + "root/Api/Policy started", + "root/Api/OnRequestHandler0/Policy started", "root/Api/ApiEventMapping0 started", ]); }); diff --git a/libs/wingsdk/test/target-sim/__snapshots__/api.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/api.test.ts.snap index ba00408b0af..d0341d9c345 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/api.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/api.test.ts.snap @@ -47,6 +47,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -196,6 +221,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -235,6 +268,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -248,6 +296,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -279,11 +340,15 @@ exports[`api handler can read the request params 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello\\",\\"query\\":{\\"foo\\":\\"bar\\",\\"bar\\":\\"baz\\"},\\"vars\\":{}}").", "GET /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -333,6 +398,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -468,6 +558,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -507,6 +605,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -520,6 +633,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -551,11 +677,15 @@ exports[`api handler can read the request path 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", "GET /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -605,6 +735,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -740,6 +895,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -779,6 +942,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -792,6 +970,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -823,11 +1014,15 @@ exports[`api handler can set response headers 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"foo\\":\\"bar\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", "GET /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -877,6 +1072,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -1012,6 +1232,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1051,6 +1279,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1064,6 +1307,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -1095,11 +1351,15 @@ exports[`api response returns Content-Type header from inflight 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", "GET /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -1149,6 +1409,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -1284,6 +1569,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1323,6 +1616,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1336,6 +1644,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -1367,11 +1688,15 @@ exports[`api response returns default Content-Type header 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", "GET /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -1421,6 +1746,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -1556,6 +1906,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1595,6 +1953,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1608,6 +1981,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -1639,6 +2025,8 @@ exports[`api supports every method type 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", @@ -1662,6 +2050,8 @@ exports[`api supports every method type 1`] = ` "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\",\\"content-length\\":\\"0\\"},\\"body\\":\\"\\",\\"method\\":\\"PATCH\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", "PATCH /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -1741,6 +2131,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -1960,6 +2375,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1999,6 +2422,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -2012,6 +2450,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -2043,11 +2494,15 @@ exports[`api with 'name' & 'age' parameter 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /:name/:age" params={"name":"akhil","age":"23"}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/akhil/23\\",\\"query\\":{},\\"vars\\":{\\"name\\":\\"akhil\\",\\"age\\":\\"23\\"}}").", "GET /:name/:age - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -2097,6 +2552,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -2249,6 +2729,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -2288,6 +2776,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -2301,6 +2804,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -2332,11 +2848,15 @@ exports[`api with 'name' parameter 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /:name" params={"name":"akhil"}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/akhil\\",\\"query\\":{},\\"vars\\":{\\"name\\":\\"akhil\\"}}").", "GET /:name - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -2386,6 +2906,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -2530,6 +3075,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -2569,6 +3122,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -2582,6 +3150,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -2649,6 +3230,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -2800,6 +3406,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -2839,6 +3453,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -2852,6 +3481,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -2883,8 +3525,11 @@ exports[`api with multiple methods on same route 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", - "root/my_api/ApiEventMapping0 started", "root/my_api/OnRequestHandler1 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", + "root/my_api/ApiEventMapping0 started", + "root/my_api/OnRequestHandler1/Policy started", "root/my_api/ApiEventMapping1 started", "Processing "GET /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", @@ -2893,11 +3538,14 @@ exports[`api with multiple methods on same route 1`] = ` "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\",\\"content-length\\":\\"0\\"},\\"body\\":\\"\\",\\"method\\":\\"POST\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", "POST /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "root/my_api/ApiEventMapping1 stopped", "Closing server on http://127.0.0.1:", "root/my_api stopped", + "root/my_api/OnRequestHandler1/Policy stopped", "root/my_api/OnRequestHandler1 stopped", ] `; @@ -2966,6 +3614,35 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler1#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -3036,6 +3713,16 @@ return class Handler { }, "type": "@winglang/sdk.sim.EventMapping", }, + { + "addr": "c8603fc16b367fc8cb05634fbb47b4a1e7f873b298", + "attrs": {}, + "path": "root/my_api/OnRequestHandler1/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler1#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c84819d7712e30f38cf7731fcfbe96cbc39c7e75d3", "attrs": {}, @@ -3146,6 +3833,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -3196,6 +3891,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -3210,6 +3920,21 @@ return class Handler { "path": "root/my_api/OnRequestHandler0", }, "OnRequestHandler1": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler1/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -3223,6 +3948,19 @@ return class Handler { "id": "OnRequestHandler1", "path": "root/my_api/OnRequestHandler1", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -3254,8 +3992,11 @@ exports[`api with multiple routes 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", - "root/my_api/ApiEventMapping0 started", "root/my_api/OnRequestHandler1 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", + "root/my_api/ApiEventMapping0 started", + "root/my_api/OnRequestHandler1/Policy started", "root/my_api/ApiEventMapping1 started", "Processing "GET /hello/world" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello/world\\",\\"query\\":{},\\"vars\\":{}}").", @@ -3264,11 +4005,14 @@ exports[`api with multiple routes 1`] = ` "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello/wingnuts\\",\\"query\\":{},\\"vars\\":{}}").", "GET /hello/wingnuts - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "root/my_api/ApiEventMapping1 stopped", "Closing server on http://127.0.0.1:", "root/my_api stopped", + "root/my_api/OnRequestHandler1/Policy stopped", "root/my_api/OnRequestHandler1 stopped", ] `; @@ -3337,6 +4081,35 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler1#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -3409,6 +4182,16 @@ return class Handler { }, "type": "@winglang/sdk.sim.EventMapping", }, + { + "addr": "c8603fc16b367fc8cb05634fbb47b4a1e7f873b298", + "attrs": {}, + "path": "root/my_api/OnRequestHandler1/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler1#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c84819d7712e30f38cf7731fcfbe96cbc39c7e75d3", "attrs": {}, @@ -3519,6 +4302,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -3569,6 +4360,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -3583,6 +4389,21 @@ return class Handler { "path": "root/my_api/OnRequestHandler0", }, "OnRequestHandler1": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler1/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -3596,6 +4417,19 @@ return class Handler { "id": "OnRequestHandler1", "path": "root/my_api/OnRequestHandler1", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -3627,11 +4461,15 @@ exports[`api with one GET route 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", "GET /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -3681,6 +4519,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -3816,6 +4679,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -3855,6 +4726,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -3868,6 +4754,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -3899,11 +4798,15 @@ exports[`api with one GET route with request params 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "GET /users/:name" params={"name":"tsuf"}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\"},\\"body\\":\\"\\",\\"method\\":\\"GET\\",\\"path\\":\\"/users/tsuf\\",\\"query\\":{},\\"vars\\":{\\"name\\":\\"tsuf\\"}}").", "GET /users/:name - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -3953,6 +4856,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -4097,6 +5025,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -4136,6 +5072,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -4149,6 +5100,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -4180,11 +5144,15 @@ exports[`api with one POST route, with body 1`] = ` "root/my_api started", "root/my_api/Endpoint started", "root/my_api/OnRequestHandler0 started", + "root/my_api/Policy started", + "root/my_api/OnRequestHandler0/Policy started", "root/my_api/ApiEventMapping0 started", "Processing "POST /hello" params={}).", "Invoke (payload="{\\"headers\\":{\\"host\\":\\"127.0.0.1:\\",\\"connection\\":\\"keep-alive\\",\\"content-type\\":\\"application/json\\",\\"accept\\":\\"*/*\\",\\"accept-language\\":\\"*\\",\\"sec-fetch-mode\\":\\"cors\\",\\"user-agent\\":\\"node\\",\\"accept-encoding\\":\\"gzip, deflate\\",\\"content-length\\":\\"25\\"},\\"body\\":\\"{\\\\\\"message\\\\\\":\\\\\\"hello world\\\\\\"}\\",\\"method\\":\\"POST\\",\\"path\\":\\"/hello\\",\\"query\\":{},\\"vars\\":{}}").", "POST /hello - 200.", "root/my_api/Endpoint stopped", + "root/my_api/Policy stopped", + "root/my_api/OnRequestHandler0/Policy stopped", "root/my_api/ApiEventMapping0 stopped", "root/my_api/OnRequestHandler0 stopped", "Closing server on http://127.0.0.1:", @@ -4234,6 +5202,31 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8b0396e20397567e34feafb703cea1bc0b968dc05", + "attrs": {}, + "path": "root/my_api/OnRequestHandler0/Policy", + "props": { + "principal": "\${wsim#root/my_api/OnRequestHandler0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c82d41b2501ac42e07e4565202a5b87a180a01c6a2", "attrs": {}, @@ -4369,6 +5362,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -4408,6 +5409,21 @@ return class Handler { "path": "root/my_api/Endpoint", }, "OnRequestHandler0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/OnRequestHandler0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -4421,6 +5437,19 @@ return class Handler { "id": "OnRequestHandler0", "path": "root/my_api/OnRequestHandler0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -4477,6 +5506,16 @@ exports[`create an api 1`] = ` }, "type": "@winglang/sdk.cloud.Endpoint", }, + { + "addr": "c8d2997625976ba9bc7be90fefe7930aebab104a2a", + "attrs": {}, + "path": "root/my_api/Policy", + "props": { + "principal": "\${wsim#root/my_api#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -4552,6 +5591,14 @@ exports[`create an api 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -4579,6 +5626,19 @@ exports[`create an api 1`] = ` "id": "Endpoint", "path": "root/my_api/Endpoint", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_api/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/bucket.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/bucket.test.ts.snap index a1f5c77fefd..56c148f70d8 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/bucket.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/bucket.test.ts.snap @@ -6,44 +6,60 @@ exports[`bucket on event creates 3 topics, and sends the right event and key in "root/my_bucket/onupdate started", "root/my_bucket/ondelete started", "root/my_bucket started", + "root/my_bucket/Policy started", "root/log_bucket started", "root/my_bucket/oncreate/OnMessage0 started", + "root/my_bucket/oncreate/Policy started", + "root/my_bucket/oncreate/OnMessage0/Policy started", "root/my_bucket/oncreate/TopicEventMapping0 started", "root/my_bucket/onupdate/OnMessage0 started", + "root/my_bucket/onupdate/Policy started", + "root/my_bucket/onupdate/OnMessage0/Policy started", "root/my_bucket/onupdate/TopicEventMapping0 started", "root/my_bucket/ondelete/OnMessage0 started", + "root/my_bucket/ondelete/Policy started", + "root/my_bucket/ondelete/OnMessage0/Policy started", "root/my_bucket/ondelete/TopicEventMapping0 started", + "root/log_bucket/Policy started", "Publish (message=a).", - "Sending message (message=a, subscriber=sim-5).", + "Sending message (message=a, subscriber=sim-6).", "InvokeAsync (payload="a").", "Put (key=a).", "Put (key=a).", "I am done", "Get (key=a).", "Publish (message=a).", - "Sending message (message=a, subscriber=sim-7).", + "Sending message (message=a, subscriber=sim-10).", "InvokeAsync (payload="a").", "Put (key=a).", "Put (key=a).", "I am done", "Get (key=a).", "Publish (message=a).", - "Sending message (message=a, subscriber=sim-9).", + "Sending message (message=a, subscriber=sim-14).", "InvokeAsync (payload="a").", "Delete (key=a).", "Put (key=a).", "I am done", "Get (key=a).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", + "root/my_bucket/oncreate/Policy stopped", "root/my_bucket/oncreate/TopicEventMapping0 stopped", "root/my_bucket/oncreate stopped", + "root/my_bucket/onupdate/Policy stopped", "root/my_bucket/onupdate/TopicEventMapping0 stopped", "root/my_bucket/onupdate stopped", + "root/my_bucket/ondelete/Policy stopped", "root/my_bucket/ondelete/TopicEventMapping0 stopped", "root/my_bucket/ondelete stopped", + "root/my_bucket/oncreate/OnMessage0/Policy stopped", "root/my_bucket/oncreate/OnMessage0 stopped", + "root/my_bucket/onupdate/OnMessage0/Policy stopped", "root/my_bucket/onupdate/OnMessage0 stopped", + "root/my_bucket/ondelete/OnMessage0/Policy stopped", "root/my_bucket/ondelete/OnMessage0 stopped", + "root/log_bucket/Policy stopped", "root/log_bucket stopped", ] `; @@ -52,9 +68,11 @@ exports[`can add file in preflight 1`] = ` [ "Adding object from preflight (key=test.txt).", "root/my_bucket started", + "root/my_bucket/Policy started", "Get (key=test.txt).", "Get (key=test.txt).", "List (prefix=null).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -80,6 +98,16 @@ exports[`can add file in preflight 2`] = ` }, "type": "@winglang/sdk.cloud.Bucket", }, + { + "addr": "c8b5ba55132964ee19331fb9f46241560e67fed76b", + "attrs": {}, + "path": "root/my_bucket/Policy", + "props": { + "principal": "\${wsim#root/my_bucket#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -155,6 +183,14 @@ exports[`can add file in preflight 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -169,6 +205,21 @@ exports[`can add file in preflight 2`] = ` "tree": { "children": { "my_bucket": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_bucket/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -197,9 +248,11 @@ exports[`can add object in preflight 1`] = ` [ "Adding object from preflight (key=greeting.txt).", "root/my_bucket started", + "root/my_bucket/Policy started", "Get (key=greeting.txt).", "Get (key=greeting.txt).", "List (prefix=null).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -225,6 +278,16 @@ exports[`can add object in preflight 2`] = ` }, "type": "@winglang/sdk.cloud.Bucket", }, + { + "addr": "c8b5ba55132964ee19331fb9f46241560e67fed76b", + "attrs": {}, + "path": "root/my_bucket/Policy", + "props": { + "principal": "\${wsim#root/my_bucket#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -300,6 +363,14 @@ exports[`can add object in preflight 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -314,6 +385,21 @@ exports[`can add object in preflight 2`] = ` "tree": { "children": { "my_bucket": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_bucket/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -357,6 +443,16 @@ exports[`create a bucket 1`] = ` }, "type": "@winglang/sdk.cloud.Bucket", }, + { + "addr": "c8b5ba55132964ee19331fb9f46241560e67fed76b", + "attrs": {}, + "path": "root/my_bucket/Policy", + "props": { + "principal": "\${wsim#root/my_bucket#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -432,6 +528,14 @@ exports[`create a bucket 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -446,6 +550,21 @@ exports[`create a bucket 1`] = ` "tree": { "children": { "my_bucket": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_bucket/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -473,7 +592,9 @@ exports[`create a bucket 1`] = ` exports[`get invalid object throws an error 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Get (key=unknown.txt).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -497,6 +618,16 @@ exports[`get invalid object throws an error 2`] = ` }, "type": "@winglang/sdk.cloud.Bucket", }, + { + "addr": "c8b5ba55132964ee19331fb9f46241560e67fed76b", + "attrs": {}, + "path": "root/my_bucket/Policy", + "props": { + "principal": "\${wsim#root/my_bucket#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -572,6 +703,14 @@ exports[`get invalid object throws an error 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -586,6 +725,21 @@ exports[`get invalid object throws an error 2`] = ` "tree": { "children": { "my_bucket": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_bucket/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -613,12 +767,14 @@ exports[`get invalid object throws an error 2`] = ` exports[`list respects prefixes 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Put (key=path/dir1/file1.txt).", "Put (key=path/dir2/file2.txt).", "List (prefix=null).", "List (prefix=path).", "List (prefix=path/dir1).", "List (prefix=path/dir2).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -626,6 +782,7 @@ exports[`list respects prefixes 1`] = ` exports[`objects can have keys that look like directories 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Put (key=foo).", "Put (key=foo/).", "Put (key=foo/bar).", @@ -637,6 +794,7 @@ exports[`objects can have keys that look like directories 1`] = ` "List (prefix=foo/bar).", "List (prefix=foo/bar/).", "List (prefix=foo/bar/baz).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -644,12 +802,14 @@ exports[`objects can have keys that look like directories 1`] = ` exports[`put and get metadata of objects from bucket 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Put (key=file1.main.w).", "Put (key=file2.txt).", "Put (key=file3.txt).", "Metadata (key=file1.main.w).", "Metadata (key=file2.txt).", "Metadata (key=file3.txt).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -657,8 +817,10 @@ exports[`put and get metadata of objects from bucket 1`] = ` exports[`put and get object from bucket 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Put (key=greeting.txt).", "Get (key=greeting.txt).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -666,10 +828,12 @@ exports[`put and get object from bucket 1`] = ` exports[`put multiple json objects and list all from bucket 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Put Json (key=greeting1.json).", "Put Json (key=greeting2.json).", "Put Json (key=greeting3.json).", "List (prefix=null).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -677,10 +841,12 @@ exports[`put multiple json objects and list all from bucket 1`] = ` exports[`put multiple objects and list all from bucket 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Put (key=greeting1.txt).", "Put (key=greeting2.txt).", "Put (key=greeting3.txt).", "List (prefix=null).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -688,8 +854,10 @@ exports[`put multiple objects and list all from bucket 1`] = ` exports[`remove object from a bucket 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Put (key=unknown.txt).", "Delete (key=unknown.txt).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -697,8 +865,10 @@ exports[`remove object from a bucket 1`] = ` exports[`remove object from a bucket with mustExist as option 1`] = ` [ "root/my_bucket started", + "root/my_bucket/Policy started", "Put (key=unknown.txt).", "Delete (key=unknown.txt).", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", ] `; @@ -707,17 +877,23 @@ exports[`removing a key will call onDelete method 1`] = ` [ "root/my_bucket/ondelete started", "root/my_bucket started", + "root/my_bucket/Policy started", "root/my_bucket/ondelete/OnMessage0 started", + "root/my_bucket/ondelete/Policy started", + "root/my_bucket/ondelete/OnMessage0/Policy started", "root/my_bucket/ondelete/TopicEventMapping0 started", "Put (key=unknown.txt).", "Publish (message=unknown.txt).", - "Sending message (message=unknown.txt, subscriber=sim-2).", + "Sending message (message=unknown.txt, subscriber=sim-3).", "InvokeAsync (payload="unknown.txt").", "Delete (key=unknown.txt).", "Received unknown.txt", + "root/my_bucket/Policy stopped", "root/my_bucket stopped", + "root/my_bucket/ondelete/Policy stopped", "root/my_bucket/ondelete/TopicEventMapping0 stopped", "root/my_bucket/ondelete stopped", + "root/my_bucket/ondelete/OnMessage0/Policy stopped", "root/my_bucket/ondelete/OnMessage0 stopped", ] `; @@ -726,12 +902,23 @@ exports[`update an object in bucket 1`] = ` [ "root/my_bucket/oncreate started", "root/my_bucket started", + "root/my_bucket/Policy started", "root/my_bucket/oncreate/OnMessage0 started", + "root/my_bucket/oncreate/Policy started", + "root/my_bucket/oncreate/OnMessage0/Policy started", "root/my_bucket/oncreate/TopicEventMapping0 started", "Publish (message=1.txt).", - "Sending message (message=1.txt, subscriber=sim-2).", + "Sending message (message=1.txt, subscriber=sim-3).", "InvokeAsync (payload="1.txt").", "Put (key=1.txt).", "Put (key=1.txt).", + "I am done", + "root/my_bucket/Policy stopped", + "root/my_bucket stopped", + "root/my_bucket/oncreate/Policy stopped", + "root/my_bucket/oncreate/TopicEventMapping0 stopped", + "root/my_bucket/oncreate stopped", + "root/my_bucket/oncreate/OnMessage0/Policy stopped", + "root/my_bucket/oncreate/OnMessage0 stopped", ] `; diff --git a/libs/wingsdk/test/target-sim/__snapshots__/counter.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/counter.test.ts.snap index 0d77770e98b..6b2d6b9b8cc 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/counter.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/counter.test.ts.snap @@ -92,6 +92,14 @@ exports[`create a counter 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -233,6 +241,14 @@ exports[`dec 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -374,6 +390,14 @@ exports[`inc 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -515,6 +539,14 @@ exports[`key dec 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -656,6 +688,14 @@ exports[`key inc 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -795,6 +835,14 @@ exports[`key set to new value 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -934,6 +982,14 @@ exports[`set to new value 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/file-counter.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/file-counter.test.ts.snap index 6371f1c2e57..9d11f3f638d 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/file-counter.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/file-counter.test.ts.snap @@ -28,7 +28,11 @@ counter: (function() { if (!simulatorUrl) { throw new Error("Missing environment variable: WING_SIMULATOR_URL"); } - return require("@winglang/sdk/lib/simulator/client").makeSimulatorClient(simulatorUrl, handle); + const caller = process.env.WING_SIMULATOR_CALLER; + if (!caller) { + throw new Error("Missing environment variable: WING_SIMULATOR_CALLER"); + } + return require("@winglang/sdk/lib/simulator/client").makeSimulatorClient(simulatorUrl, handle, caller); })(), bucket: (function() { let handle = process.env.BUCKET_HANDLE_5f2a41c8; @@ -39,7 +43,11 @@ bucket: (function() { if (!simulatorUrl) { throw new Error("Missing environment variable: WING_SIMULATOR_URL"); } - return require("@winglang/sdk/lib/simulator/client").makeSimulatorClient(simulatorUrl, handle); + const caller = process.env.WING_SIMULATOR_CALLER; + if (!caller) { + throw new Error("Missing environment variable: WING_SIMULATOR_CALLER"); + } + return require("@winglang/sdk/lib/simulator/client").makeSimulatorClient(simulatorUrl, handle, caller); })() }), args: {} })); return await $handler.handle(event); @@ -66,6 +74,54 @@ bucket: (function() { }, "simulator.json": { "resources": [ + { + "addr": "c86eb36bbe6e764a632afaaea5db2d4bd693c92624", + "attrs": {}, + "path": "root/HelloWorld/Bucket/Policy", + "props": { + "principal": "\${wsim#root/HelloWorld/Bucket#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c86b009930462795eeb90e647a56dbfc5356d9ea80", + "attrs": {}, + "path": "root/HelloWorld/Queue/Policy", + "props": { + "principal": "\${wsim#root/HelloWorld/Queue#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/HelloWorld/Queue/SetConsumer0#attrs.handle}", + }, + { + "operation": "hasAvailableWorkers", + "resourceHandle": "\${wsim#root/HelloWorld/Queue/SetConsumer0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c88f4eae8103e33f1cf696aa3dad78ce4f1e5a2caa", + "attrs": {}, + "path": "root/HelloWorld/Queue/SetConsumer0/Policy", + "props": { + "principal": "\${wsim#root/HelloWorld/Queue/SetConsumer0#attrs.handle}", + "statements": [ + { + "operation": "inc", + "resourceHandle": "\${wsim#root/HelloWorld/Counter#attrs.handle}", + }, + { + "operation": "put", + "resourceHandle": "\${wsim#root/HelloWorld/Bucket#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c87855e817fa3df0d5ce8ae290bf53c8ce4ecd8d46", "attrs": {}, @@ -208,6 +264,14 @@ bucket: (function() { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -224,6 +288,21 @@ bucket: (function() { "HelloWorld": { "children": { "Bucket": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/HelloWorld/Bucket/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -249,6 +328,19 @@ bucket: (function() { }, "Queue": { "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/HelloWorld/Queue/Policy", + }, "QueueEventMapping0": { "constructInfo": { "fqn": "constructs.Construct", @@ -261,6 +353,21 @@ bucket: (function() { "path": "root/HelloWorld/Queue/QueueEventMapping0", }, "SetConsumer0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/HelloWorld/Queue/SetConsumer0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/function.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/function.test.ts.snap index f15ffe22fb8..685cdcef273 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/function.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/function.test.ts.snap @@ -1,16 +1,5 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`__dirname and __filename cannot be used within inflight code 1`] = ` -[ - "root/Function.0 started", - "root/Function.1 started", - "Warning: __dirname and __filename cannot be used within bundled cloud functions. There may be unexpected behavior.", - "Warning: __dirname and __filename cannot be used within bundled cloud functions. There may be unexpected behavior.", - "Invoke (payload=undefined).", - "Invoke (payload=undefined).", -] -`; - exports[`create a function 1`] = ` { ".wing/my_function_c85c4e0e.js": ""use strict"; @@ -64,6 +53,16 @@ async handle(event) { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c8d421ed6ca2ddf857d835791bcde9240c8682a8d9", + "attrs": {}, + "path": "root/my_function/Policy", + "props": { + "principal": "\${wsim#root/my_function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -139,6 +138,14 @@ async handle(event) { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -153,6 +160,21 @@ async handle(event) { "tree": { "children": { "my_function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -180,7 +202,9 @@ async handle(event) { exports[`invoke function fails 1`] = ` [ "root/my_function started", + "root/my_function/Policy started", "Invoke (payload="{\\"name\\":\\"alice\\"}").", + "root/my_function/Policy stopped", "root/my_function stopped", ] `; @@ -236,6 +260,16 @@ async handle(event) { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c8d421ed6ca2ddf857d835791bcde9240c8682a8d9", + "attrs": {}, + "path": "root/my_function/Policy", + "props": { + "principal": "\${wsim#root/my_function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -311,6 +345,14 @@ async handle(event) { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -325,6 +367,21 @@ async handle(event) { "tree": { "children": { "my_function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -352,7 +409,9 @@ async handle(event) { exports[`invoke function succeeds 1`] = ` [ "root/my_function started", + "root/my_function/Policy started", "Invoke (payload="{\\"name\\":\\"Alice\\"}").", + "root/my_function/Policy stopped", "root/my_function stopped", ] `; @@ -408,6 +467,16 @@ async handle(event) { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c8d421ed6ca2ddf857d835791bcde9240c8682a8d9", + "attrs": {}, + "path": "root/my_function/Policy", + "props": { + "principal": "\${wsim#root/my_function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -483,6 +552,14 @@ async handle(event) { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -497,6 +574,21 @@ async handle(event) { "tree": { "children": { "my_function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -524,7 +616,9 @@ async handle(event) { exports[`invoke function with environment variables 1`] = ` [ "root/my_function started", + "root/my_function/Policy started", "Invoke (payload="{\\"name\\":\\"Alice\\"}").", + "root/my_function/Policy stopped", "root/my_function stopped", ] `; @@ -582,6 +676,16 @@ async handle(event) { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c8d421ed6ca2ddf857d835791bcde9240c8682a8d9", + "attrs": {}, + "path": "root/my_function/Policy", + "props": { + "principal": "\${wsim#root/my_function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -657,6 +761,14 @@ async handle(event) { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -671,6 +783,21 @@ async handle(event) { "tree": { "children": { "my_function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -698,7 +825,9 @@ async handle(event) { exports[`invoke function with process.exit(1) 1`] = ` [ "root/my_function started", + "root/my_function/Policy started", "Invoke (payload="{}").", + "root/my_function/Policy stopped", "root/my_function stopped", ] `; @@ -744,6 +873,16 @@ async handle() { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c8d421ed6ca2ddf857d835791bcde9240c8682a8d9", + "attrs": {}, + "path": "root/my_function/Policy", + "props": { + "principal": "\${wsim#root/my_function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -819,6 +958,14 @@ async handle() { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -833,6 +980,21 @@ async handle() { "tree": { "children": { "my_function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -966,6 +1128,16 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c80ba70b2cdb9a19bee761f329d38a2f8fe60dfd96", + "attrs": {}, + "path": "root/Function.0/Policy", + "props": { + "principal": "\${wsim#root/Function.0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c89ed254f66166d83153cc0a4952a15be63d47b0d2", "attrs": {}, @@ -979,6 +1151,16 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82b947659316c604ceae225ba418b0d37542a5ba9", + "attrs": {}, + "path": "root/Function.1/Policy", + "props": { + "principal": "\${wsim#root/Function.1#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c8cd6c39da22910102d0cfeb2cb96f2160fa79e517", "attrs": {}, @@ -992,6 +1174,16 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c84e1c1344ab5edfebbe25048f337b36bf0c9aed39", + "attrs": {}, + "path": "root/Function.2/Policy", + "props": { + "principal": "\${wsim#root/Function.2#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c8badafa75a67ff66740e0c5fbbb392ab574b52b3c", "attrs": {}, @@ -1005,6 +1197,16 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c808a620b5341fa15dc763e8b6ba15ff0ebfcc6240", + "attrs": {}, + "path": "root/Function.3/Policy", + "props": { + "principal": "\${wsim#root/Function.3#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -1080,6 +1282,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1094,6 +1304,21 @@ return class Handler { "tree": { "children": { "Function.0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function.0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1106,6 +1331,21 @@ return class Handler { "path": "root/Function.0", }, "Function.1": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function.1/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1118,6 +1358,21 @@ return class Handler { "path": "root/Function.1", }, "Function.2": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function.2/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1130,6 +1385,21 @@ return class Handler { "path": "root/Function.2", }, "Function.3": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function.3/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/immutable-capture.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/immutable-capture.test.ts.snap index 048de7a441c..afd9b0a28a7 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/immutable-capture.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/immutable-capture.test.ts.snap @@ -43,6 +43,16 @@ my_capture: ["hello","dude"] }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -118,6 +128,14 @@ my_capture: ["hello","dude"] "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -132,6 +150,21 @@ my_capture: ["hello","dude"] "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -199,6 +232,16 @@ my_array: [(new (require("[REDACTED]/wingsdk/src/std/duration.js").Duration)(600 }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -274,6 +317,14 @@ my_array: [(new (require("[REDACTED]/wingsdk/src/std/duration.js").Duration)(600 "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -288,6 +339,21 @@ my_array: [(new (require("[REDACTED]/wingsdk/src/std/duration.js").Duration)(600 "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -354,6 +420,16 @@ my_array: [new Map([["foo",1],["bar",2]]),new Map([["foo",3],["bar",4]])] }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -429,6 +505,14 @@ my_array: [new Map([["foo",1],["bar",2]]),new Map([["foo",3],["bar",4]])] "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -443,6 +527,21 @@ my_array: [new Map([["foo",1],["bar",2]]),new Map([["foo",3],["bar",4]])] "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -508,6 +607,16 @@ my_capture: false }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -583,6 +692,14 @@ my_capture: false "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -597,6 +714,21 @@ my_capture: false "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -664,6 +796,16 @@ my_capture: (new (require("[REDACTED]/wingsdk/src/std/duration.js").Duration)(72 }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -739,6 +881,14 @@ my_capture: (new (require("[REDACTED]/wingsdk/src/std/duration.js").Duration)(72 "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -753,6 +903,21 @@ my_capture: (new (require("[REDACTED]/wingsdk/src/std/duration.js").Duration)(72 "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -822,6 +987,16 @@ my_capture: new Map([["foo",123],["bar",456]]) }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -897,6 +1072,14 @@ my_capture: new Map([["foo",123],["bar",456]]) "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -911,6 +1094,21 @@ my_capture: new Map([["foo",123],["bar",456]]) "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -982,6 +1180,16 @@ my_map: new Map([["foo",[1,2]],["bar",[3,4]]]) }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -1057,6 +1265,14 @@ my_map: new Map([["foo",[1,2]],["bar",[3,4]]]) "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1071,6 +1287,21 @@ my_map: new Map([["foo",[1,2]],["bar",[3,4]]]) "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1139,6 +1370,16 @@ my_map: new Map([["foo",[(new (require("[REDACTED]/wingsdk/src/std/duration.js") }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -1214,6 +1455,14 @@ my_map: new Map([["foo",[(new (require("[REDACTED]/wingsdk/src/std/duration.js") "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1228,6 +1477,21 @@ my_map: new Map([["foo",[(new (require("[REDACTED]/wingsdk/src/std/duration.js") "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1293,6 +1557,16 @@ my_capture: 123 }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -1368,6 +1642,14 @@ my_capture: 123 "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1382,6 +1664,21 @@ my_capture: 123 "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1450,6 +1747,16 @@ my_capture: new Set(["boom","bam","bang"]) }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -1525,6 +1832,14 @@ my_capture: new Set(["boom","bam","bang"]) "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1539,6 +1854,21 @@ my_capture: new Set(["boom","bam","bang"]) "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1606,6 +1936,16 @@ my_set: new Set([(new (require("[REDACTED]/wingsdk/src/std/duration.js").Duratio }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -1681,6 +2021,14 @@ my_set: new Set([(new (require("[REDACTED]/wingsdk/src/std/duration.js").Duratio "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1695,6 +2043,21 @@ my_set: new Set([(new (require("[REDACTED]/wingsdk/src/std/duration.js").Duratio "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1761,6 +2124,16 @@ my_capture: "bam bam bam" }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -1836,6 +2209,14 @@ my_capture: "bam bam bam" "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1850,6 +2231,21 @@ my_capture: "bam bam bam" "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1918,6 +2314,16 @@ my_capture: {"hello": "dude","world": "cup","foo": "bar",} }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -1993,6 +2399,14 @@ my_capture: {"hello": "dude","world": "cup","foo": "bar",} "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -2007,6 +2421,21 @@ my_capture: {"hello": "dude","world": "cup","foo": "bar",} "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -2075,6 +2504,16 @@ my_struct: {"foo": new Map([["foo",1],["bar",2]]),"bar": new Map([["foo",3],["ba }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c82c6881e1717b3b64913c3a5c4d7843012f2897e9", + "attrs": {}, + "path": "root/Function/Policy", + "props": { + "principal": "\${wsim#root/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -2150,6 +2589,14 @@ my_struct: {"foo": new Map([["foo",1],["bar",2]]),"bar": new Map([["foo",3],["ba "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -2164,6 +2611,21 @@ my_struct: {"foo": new Map([["foo",1],["bar",2]]),"bar": new Map([["foo",3],["ba "tree": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/on-deploy.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/on-deploy.test.ts.snap index c8e80855916..8f0db48a5f3 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/on-deploy.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/on-deploy.test.ts.snap @@ -38,11 +38,22 @@ return class Handler { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c84ce37dba3dd1bd3d5c4ab27cb72c54e2b1a75821", + "attrs": {}, + "path": "root/my_on_deploy/Function/Policy", + "props": { + "principal": "\${wsim#root/my_on_deploy/Function#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c8e2618b976544550a8396a3817f0bad07099f7050", "attrs": {}, "deps": [ "root/my_on_deploy/Function", + "root/my_on_deploy/Function/Policy", ], "path": "root/my_on_deploy", "props": { @@ -125,6 +136,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -141,6 +160,21 @@ return class Handler { "my_on_deploy": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_on_deploy/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -181,11 +215,13 @@ return class Handler { exports[`create an OnDeploy 2`] = ` [ "root/my_on_deploy/Function started", + "root/my_on_deploy/Function/Policy started", "super duper success", "Invoke (payload=undefined).", "OnDeploy invoked.", "root/my_on_deploy started", "root/my_on_deploy stopped", + "root/my_on_deploy/Function/Policy stopped", "root/my_on_deploy/Function stopped", ] `; diff --git a/libs/wingsdk/test/target-sim/__snapshots__/queue.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/queue.test.ts.snap index 642f485ebdc..cef3a1a4097 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/queue.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/queue.test.ts.snap @@ -18,6 +18,16 @@ exports[`create a queue 1`] = ` }, "type": "@winglang/sdk.cloud.Queue", }, + { + "addr": "c88a4c68047871c2d322479c886423828e8119d85c", + "attrs": {}, + "path": "root/my_queue/Policy", + "props": { + "principal": "\${wsim#root/my_queue#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -93,6 +103,14 @@ exports[`create a queue 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -107,6 +125,21 @@ exports[`create a queue 1`] = ` "tree": { "children": { "my_queue": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_queue/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -585,7 +618,9 @@ async handle(message) { exports[`push rejects empty message 1`] = ` [ "root/my_queue started", + "root/my_queue/Policy started", "Push (messages=).", + "root/my_queue/Policy stopped", "root/my_queue stopped", ] `; @@ -608,6 +643,16 @@ exports[`push rejects empty message 2`] = ` }, "type": "@winglang/sdk.cloud.Queue", }, + { + "addr": "c88a4c68047871c2d322479c886423828e8119d85c", + "attrs": {}, + "path": "root/my_queue/Policy", + "props": { + "principal": "\${wsim#root/my_queue#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -683,6 +728,14 @@ exports[`push rejects empty message 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -697,6 +750,21 @@ exports[`push rejects empty message 2`] = ` "tree": { "children": { "my_queue": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_queue/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -724,11 +792,13 @@ exports[`push rejects empty message 2`] = ` exports[`queue batch size of 2, purge the queue 1`] = ` [ "root/my_queue started", + "root/my_queue/Policy started", "Push (messages=A).", "Push (messages=B).", "ApproxSize ().", "Purge ().", "ApproxSize ().", + "root/my_queue/Policy stopped", "root/my_queue stopped", ] `; @@ -751,6 +821,16 @@ exports[`queue batch size of 2, purge the queue 2`] = ` }, "type": "@winglang/sdk.cloud.Queue", }, + { + "addr": "c88a4c68047871c2d322479c886423828e8119d85c", + "attrs": {}, + "path": "root/my_queue/Policy", + "props": { + "principal": "\${wsim#root/my_queue#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -826,6 +906,14 @@ exports[`queue batch size of 2, purge the queue 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -840,6 +928,21 @@ exports[`queue batch size of 2, purge the queue 2`] = ` "tree": { "children": { "my_queue": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_queue/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -895,7 +998,11 @@ queue: (function() { if (!simulatorUrl) { throw new Error("Missing environment variable: WING_SIMULATOR_URL"); } - return require("@winglang/sdk/lib/simulator/client").makeSimulatorClient(simulatorUrl, handle); + const caller = process.env.WING_SIMULATOR_CALLER; + if (!caller) { + throw new Error("Missing environment variable: WING_SIMULATOR_CALLER"); + } + return require("@winglang/sdk/lib/simulator/client").makeSimulatorClient(simulatorUrl, handle, caller); })() })); return await $handler.handle(event); @@ -939,6 +1046,35 @@ async handle(message) { }, "simulator.json": { "resources": [ + { + "addr": "c88a4c68047871c2d322479c886423828e8119d85c", + "attrs": {}, + "path": "root/my_queue/Policy", + "props": { + "principal": "\${wsim#root/my_queue#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_queue/SetConsumer0#attrs.handle}", + }, + { + "operation": "hasAvailableWorkers", + "resourceHandle": "\${wsim#root/my_queue/SetConsumer0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c850ec3b050199141fa07ce182e2e0711e60d2d193", + "attrs": {}, + "path": "root/my_queue/SetConsumer0/Policy", + "props": { + "principal": "\${wsim#root/my_queue/SetConsumer0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c8e33b9b91c909e579b9d3d703146eb66c2a657ffc", "attrs": {}, @@ -997,11 +1133,27 @@ async handle(message) { }, "type": "@winglang/sdk.cloud.Function", }, + { + "addr": "c8a0157ce3fdc8f4da43f974ef4b722745f359650f", + "attrs": {}, + "path": "root/my_queue_messages/Function/Policy", + "props": { + "principal": "\${wsim#root/my_queue_messages/Function#attrs.handle}", + "statements": [ + { + "operation": "push", + "resourceHandle": "\${wsim#root/my_queue#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c8e2354407fd3536187725c2b37c5327f47bb841e9", "attrs": {}, "deps": [ "root/my_queue_messages/Function", + "root/my_queue_messages/Function/Policy", ], "path": "root/my_queue_messages", "props": { @@ -1084,6 +1236,14 @@ async handle(message) { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1099,6 +1259,19 @@ async handle(message) { "children": { "my_queue": { "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_queue/Policy", + }, "QueueEventMapping0": { "constructInfo": { "fqn": "constructs.Construct", @@ -1111,6 +1284,21 @@ async handle(message) { "path": "root/my_queue/QueueEventMapping0", }, "SetConsumer0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_queue/SetConsumer0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1138,6 +1326,21 @@ async handle(message) { "my_queue_messages": { "children": { "Function": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_queue_messages/Function/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -1211,6 +1414,35 @@ async handle(message) { }, "simulator.json": { "resources": [ + { + "addr": "c88a4c68047871c2d322479c886423828e8119d85c", + "attrs": {}, + "path": "root/my_queue/Policy", + "props": { + "principal": "\${wsim#root/my_queue#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_queue/SetConsumer0#attrs.handle}", + }, + { + "operation": "hasAvailableWorkers", + "resourceHandle": "\${wsim#root/my_queue/SetConsumer0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c850ec3b050199141fa07ce182e2e0711e60d2d193", + "attrs": {}, + "path": "root/my_queue/SetConsumer0/Policy", + "props": { + "principal": "\${wsim#root/my_queue/SetConsumer0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c8e33b9b91c909e579b9d3d703146eb66c2a657ffc", "attrs": {}, @@ -1326,6 +1558,14 @@ async handle(message) { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -1341,6 +1581,19 @@ async handle(message) { "children": { "my_queue": { "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_queue/Policy", + }, "QueueEventMapping0": { "constructInfo": { "fqn": "constructs.Construct", @@ -1353,6 +1606,21 @@ async handle(message) { "path": "root/my_queue/QueueEventMapping0", }, "SetConsumer0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_queue/SetConsumer0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/redis.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/redis.test.ts.snap index f20b4825304..69133a45443 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/redis.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/redis.test.ts.snap @@ -104,6 +104,14 @@ exports[`create a Redis resource 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/schedule.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/schedule.test.ts.snap index c845a045772..1b3ff0eaf05 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/schedule.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/schedule.test.ts.snap @@ -17,6 +17,16 @@ exports[`create a schedule 1`] = ` }, "type": "@winglang/sdk.cloud.Schedule", }, + { + "addr": "c8c7f555c253f79a2cdcd8a13c6772cfd654e2bf0b", + "attrs": {}, + "path": "root/my_schedule/Policy", + "props": { + "principal": "\${wsim#root/my_schedule#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -92,6 +102,14 @@ exports[`create a schedule 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -106,6 +124,21 @@ exports[`create a schedule 1`] = ` "tree": { "children": { "my_schedule": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_schedule/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -164,6 +197,31 @@ console.log("Hello from schedule!"); }, "simulator.json": { "resources": [ + { + "addr": "c8c7f555c253f79a2cdcd8a13c6772cfd654e2bf0b", + "attrs": {}, + "path": "root/my_schedule/Policy", + "props": { + "principal": "\${wsim#root/my_schedule#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_schedule/OnTick0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8d61fcab25f1c27fcb0f0ba29e4888a7041c8029f", + "attrs": {}, + "path": "root/my_schedule/OnTick0/Policy", + "props": { + "principal": "\${wsim#root/my_schedule/OnTick0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c83eddbe8512d15b84969a611d4b5ca9ce55e1f808", "attrs": {}, @@ -276,6 +334,14 @@ console.log("Hello from schedule!"); "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -292,6 +358,21 @@ console.log("Hello from schedule!"); "my_schedule": { "children": { "OnTick0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_schedule/OnTick0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -315,6 +396,19 @@ console.log("Hello from schedule!"); "id": "OnTickMapping0", "path": "root/my_schedule/OnTickMapping0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_schedule/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -374,6 +468,31 @@ console.log("Hello from schedule!"); }, "simulator.json": { "resources": [ + { + "addr": "c8c7f555c253f79a2cdcd8a13c6772cfd654e2bf0b", + "attrs": {}, + "path": "root/my_schedule/Policy", + "props": { + "principal": "\${wsim#root/my_schedule#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_schedule/OnTick0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8d61fcab25f1c27fcb0f0ba29e4888a7041c8029f", + "attrs": {}, + "path": "root/my_schedule/OnTick0/Policy", + "props": { + "principal": "\${wsim#root/my_schedule/OnTick0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c83eddbe8512d15b84969a611d4b5ca9ce55e1f808", "attrs": {}, @@ -486,6 +605,14 @@ console.log("Hello from schedule!"); "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -502,6 +629,21 @@ console.log("Hello from schedule!"); "my_schedule": { "children": { "OnTick0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_schedule/OnTick0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -525,6 +667,19 @@ console.log("Hello from schedule!"); "id": "OnTickMapping0", "path": "root/my_schedule/OnTickMapping0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_schedule/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", @@ -584,6 +739,31 @@ console.log("Hello from schedule!"); }, "simulator.json": { "resources": [ + { + "addr": "c8c7f555c253f79a2cdcd8a13c6772cfd654e2bf0b", + "attrs": {}, + "path": "root/my_schedule/Policy", + "props": { + "principal": "\${wsim#root/my_schedule#attrs.handle}", + "statements": [ + { + "operation": "invoke", + "resourceHandle": "\${wsim#root/my_schedule/OnTick0#attrs.handle}", + }, + ], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c8d61fcab25f1c27fcb0f0ba29e4888a7041c8029f", + "attrs": {}, + "path": "root/my_schedule/OnTick0/Policy", + "props": { + "principal": "\${wsim#root/my_schedule/OnTick0#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, { "addr": "c83eddbe8512d15b84969a611d4b5ca9ce55e1f808", "attrs": {}, @@ -696,6 +876,14 @@ console.log("Hello from schedule!"); "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -712,6 +900,21 @@ console.log("Hello from schedule!"); "my_schedule": { "children": { "OnTick0": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_schedule/OnTick0/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", @@ -735,6 +938,19 @@ console.log("Hello from schedule!"); "id": "OnTickMapping0", "path": "root/my_schedule/OnTickMapping0", }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_schedule/Policy", + }, }, "constructInfo": { "fqn": "constructs.Construct", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/secret.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/secret.test.ts.snap index 50ee1bf1a06..debe797f8d9 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/secret.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/secret.test.ts.snap @@ -92,6 +92,14 @@ exports[`create a secret 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/service.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/service.test.ts.snap index 8ec8e96fba0..f47c105b1ca 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/service.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/service.test.ts.snap @@ -45,12 +45,35 @@ return class Handler { "attrs": {}, "path": "root/my_service", "props": { - "autoStart": true, "environmentVariables": {}, "sourceCodeFile": ".wing/my_service_c815f66e.js", }, "type": "@winglang/sdk.cloud.Service", }, + { + "addr": "c845f08fe23811b5ba949f822a6bc3077a050f801b", + "attrs": {}, + "path": "root/my_service/Policy", + "props": { + "principal": "\${wsim#root/my_service#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, + { + "addr": "c810e24e6e3ab8b88ceddbbe1ac7323d46de30a969", + "attrs": {}, + "deps": [ + "root/my_service", + "root/my_service/Policy", + ], + "path": "root/my_service/Helper", + "props": { + "autoStart": true, + "service": "\${wsim#root/my_service#attrs.handle}", + }, + "type": "@winglang/sdk.sim.ServiceHelper", + }, ], "sdkVersion": "0.0.0", "types": { @@ -126,6 +149,14 @@ return class Handler { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -140,6 +171,32 @@ return class Handler { "tree": { "children": { "my_service": { + "children": { + "Helper": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "hidden": true, + }, + "id": "Helper", + "path": "root/my_service/Helper", + }, + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_service/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/table.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/table.test.ts.snap index 4ac0d3b25cd..470f510adec 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/table.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/table.test.ts.snap @@ -113,6 +113,14 @@ exports[`can add row in preflight 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -249,6 +257,14 @@ exports[`create a table 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -395,6 +411,14 @@ exports[`get row 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -539,6 +563,14 @@ exports[`insert row 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -685,6 +717,14 @@ exports[`list table 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -830,6 +870,14 @@ exports[`tryGet row 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -978,6 +1026,14 @@ exports[`update row 2`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/test.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/test.test.ts.snap index 9fa84c5ea50..05c7d3fded0 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/test.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/test.test.ts.snap @@ -55,6 +55,16 @@ async handle(event) { }, "type": "@winglang/sdk.std.TestRunner", }, + { + "addr": "c8e9f1ae266f81e04ffcbb951317b09fa72e8ad7cb", + "attrs": {}, + "path": "root/env0/test:my_test/Handler/Policy", + "props": { + "principal": "\${wsim#root/env0/test:my_test/Handler#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -130,6 +140,14 @@ async handle(event) { "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -161,6 +179,21 @@ async handle(event) { "test:my_test": { "children": { "Handler": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/env0/test:my_test/Handler/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", diff --git a/libs/wingsdk/test/target-sim/__snapshots__/topic-producer.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/topic-producer.test.ts.snap index 22c43627674..56a208842d6 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/topic-producer.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/topic-producer.test.ts.snap @@ -2,16 +2,23 @@ exports[`publishing messages to topic 1`] = ` [ - "root/TopicTester/MyTopic/OnMessage0 started", "root/TopicTester/MyTopic started", + "root/TopicTester/MyTopic/OnMessage0 started", + "root/TopicTester/MyTopic/Policy started", + "root/TopicTester/MyTopic/OnMessage0/Policy started", "root/TopicTester/MyTopic/TopicEventMapping0 started", "root/TopicTester/Function started", + "root/TopicTester/Function/Policy started", "Publish (message=ABC).", - "Sending message (message=ABC, subscriber=sim-0).", + "Sending message (message=ABC, subscriber=sim-1).", "InvokeAsync (payload="ABC").", "Invoke (payload="ABC").", + "Message received", + "root/TopicTester/MyTopic/Policy stopped", + "root/TopicTester/MyTopic/OnMessage0/Policy stopped", "root/TopicTester/MyTopic/TopicEventMapping0 stopped", "root/TopicTester/MyTopic/OnMessage0 stopped", + "root/TopicTester/Function/Policy stopped", "root/TopicTester/Function stopped", "root/TopicTester/MyTopic stopped", ] diff --git a/libs/wingsdk/test/target-sim/__snapshots__/topic.test.ts.snap b/libs/wingsdk/test/target-sim/__snapshots__/topic.test.ts.snap index f846cbccf14..be384dbb3fb 100644 --- a/libs/wingsdk/test/target-sim/__snapshots__/topic.test.ts.snap +++ b/libs/wingsdk/test/target-sim/__snapshots__/topic.test.ts.snap @@ -15,6 +15,16 @@ exports[`create a topic 1`] = ` "props": {}, "type": "@winglang/sdk.cloud.Topic", }, + { + "addr": "c8635ef174eab9aa010e5bed09a712307a6b70e731", + "attrs": {}, + "path": "root/my_topic/Policy", + "props": { + "principal": "\${wsim#root/my_topic#attrs.handle}", + "statements": [], + }, + "type": "@winglang/sdk.sim.Policy", + }, ], "sdkVersion": "0.0.0", "types": { @@ -90,6 +100,14 @@ exports[`create a topic 1`] = ` "className": "EventMapping", "sourcePath": "/event-mapping.inflight.js", }, + "@winglang/sdk.sim.Policy": { + "className": "Policy", + "sourcePath": "/policy.inflight.js", + }, + "@winglang/sdk.sim.ServiceHelper": { + "className": "ServiceHelper", + "sourcePath": "/service.inflight.js", + }, "@winglang/sdk.sim.State": { "className": "State", "sourcePath": "/state.inflight.js", @@ -104,6 +122,21 @@ exports[`create a topic 1`] = ` "tree": { "children": { "my_topic": { + "children": { + "Policy": { + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0", + }, + "display": { + "description": "A simulated resource policy", + "hidden": true, + "title": "Policy", + }, + "id": "Policy", + "path": "root/my_topic/Policy", + }, + }, "constructInfo": { "fqn": "constructs.Construct", "version": "10.3.0", diff --git a/libs/wingsdk/test/target-sim/app.test.ts b/libs/wingsdk/test/target-sim/app.test.ts index 13ddf565a43..b071c6f0526 100644 --- a/libs/wingsdk/test/target-sim/app.test.ts +++ b/libs/wingsdk/test/target-sim/app.test.ts @@ -48,7 +48,10 @@ test("tests do not synthesize functions when test mode is off", async () => { await s.stop(); // THEN - expect(resources.sort()).toEqual(["root/Default/my_bucket"]); + expect(resources.sort()).toEqual([ + "root/Default/my_bucket", + "root/Default/my_bucket/Policy", + ]); }); test("tests are synthesized into individual environments when test mode is on", async () => { @@ -73,8 +76,12 @@ test("tests are synthesized into individual environments when test mode is on", expect(resources.sort()).toEqual([ "root/cloud.TestRunner", "root/env0/my_bucket", + "root/env0/my_bucket/Policy", "root/env0/test:my_test1/Handler", + "root/env0/test:my_test1/Handler/Policy", "root/env1/my_bucket", + "root/env1/my_bucket/Policy", "root/env1/test:my_test2/Handler", + "root/env1/test:my_test2/Handler/Policy", ]); }); diff --git a/libs/wingsdk/test/target-sim/bucket.test.ts b/libs/wingsdk/test/target-sim/bucket.test.ts index 959449fac72..5d07e2f1a34 100644 --- a/libs/wingsdk/test/target-sim/bucket.test.ts +++ b/libs/wingsdk/test/target-sim/bucket.test.ts @@ -39,7 +39,9 @@ test("update an object in bucket", async () => { // GIVEN const app = new SimApp(); const bucket = new cloud.Bucket(app, "my_bucket"); - const testInflight = Testing.makeHandler("async handle() {}"); + const testInflight = Testing.makeHandler( + "async handle() { console.log('I am done'); }" + ); bucket.onCreate(testInflight); const s = await app.startSimulator(); @@ -48,13 +50,17 @@ test("update an object in bucket", async () => { // WHEN await client.put(KEY, JSON.stringify({ msg: "Hello world 1!" })); - await waitUntilTraceCount(s, 4, (trace) => trace.data.message.includes(KEY)); await client.put(KEY, JSON.stringify({ msg: "Hello world 2!" })); - await waitUntilTraceCount(s, 5, (trace) => trace.data.message.includes(KEY)); + await waitUntilTraceCount(s, 1, (trace) => + trace.data.message.includes(`I am done`) + ); // THEN - expect(listMessages(s)).toMatchSnapshot(); await s.stop(); + expect(listMessages(s)).toMatchSnapshot(); + // The bucket notification topic should only publish one message, since the + // second put() call counts as an update, not a create. + expect(listMessages(s).filter((m) => m.includes(`Publish`))).toHaveLength(1); }); test("bucket on event creates 3 topics, and sends the right event and key in the event handlers", async () => { @@ -331,7 +337,7 @@ test("get invalid object throws an error", async () => { await s.stop(); expect(listMessages(s)).toMatchSnapshot(); - expect(s.listTraces()[1].data.status).toEqual("failure"); + expect(s.listTraces()[2].data.status).toEqual("failure"); expect(app.snapshot()).toMatchSnapshot(); }); diff --git a/libs/wingsdk/test/target-sim/function.test.ts b/libs/wingsdk/test/target-sim/function.test.ts index a140e353e37..d791254362c 100644 --- a/libs/wingsdk/test/target-sim/function.test.ts +++ b/libs/wingsdk/test/target-sim/function.test.ts @@ -130,7 +130,7 @@ test("invoke function fails", async () => { await s.stop(); expect(listMessages(s)).toMatchSnapshot(); - expect(s.listTraces()[1].data.error).toMatchObject({ + expect(s.listTraces()[2].data.error).toMatchObject({ message: "Name must start with uppercase letter", }); expect(app.snapshot()).toMatchSnapshot(); @@ -190,13 +190,13 @@ test("invoke function with process.exit(1)", async () => { // WHEN const PAYLOAD = {}; await expect(client.invoke(JSON.stringify(PAYLOAD))).rejects.toThrow( - "Process exited with code 1" + "Process exited with code 1, signal null" ); // THEN await s.stop(); expect(listMessages(s)).toMatchSnapshot(); - expect(s.listTraces()[1].data.error).toMatchObject({ - message: "Process exited with code 1", + expect(s.listTraces()[2].data.error).toMatchObject({ + message: "Process exited with code 1, signal null", }); expect(app.snapshot()).toMatchSnapshot(); }); @@ -247,5 +247,13 @@ test("__dirname and __filename cannot be used within inflight code", async () => await dirnameInvoker(s); await filenameInvoker(s); - expect(listMessages(s)).toMatchSnapshot(); + await s.stop(); + + expect( + listMessages(s).filter((m) => + m.includes( + "Warning: __dirname and __filename cannot be used within bundled cloud functions." + ) + ) + ).toHaveLength(2); }); diff --git a/libs/wingsdk/test/target-sim/on-deploy.test.ts b/libs/wingsdk/test/target-sim/on-deploy.test.ts index 1aa9077b3fe..a2df5e6042e 100644 --- a/libs/wingsdk/test/target-sim/on-deploy.test.ts +++ b/libs/wingsdk/test/target-sim/on-deploy.test.ts @@ -18,7 +18,7 @@ test("create an OnDeploy", async () => { attrs: { handle: expect.any(String), }, - deps: ["root/my_on_deploy/Function"], + deps: ["root/my_on_deploy/Function", "root/my_on_deploy/Function/Policy"], path: "root/my_on_deploy", addr: expect.any(String), props: { diff --git a/libs/wingsdk/test/target-sim/queue.test.ts b/libs/wingsdk/test/target-sim/queue.test.ts index 8941c55c0bc..047e5ee6b4d 100644 --- a/libs/wingsdk/test/target-sim/queue.test.ts +++ b/libs/wingsdk/test/target-sim/queue.test.ts @@ -369,6 +369,6 @@ test("push rejects empty message", async () => { await s.stop(); expect(listMessages(s)).toMatchSnapshot(); - expect(s.listTraces()[1].data.status).toEqual("failure"); + expect(s.listTraces()[2].data.status).toEqual("failure"); expect(app.snapshot()).toMatchSnapshot(); }); diff --git a/libs/wingsdk/test/target-sim/service.test.ts b/libs/wingsdk/test/target-sim/service.test.ts index b783cc91e63..7848eacad36 100644 --- a/libs/wingsdk/test/target-sim/service.test.ts +++ b/libs/wingsdk/test/target-sim/service.test.ts @@ -32,7 +32,6 @@ test("create a service with on start method", async () => { props: { sourceCodeFile: expect.any(String), environmentVariables: {}, - autoStart: true, }, type: cloud.SERVICE_FQN, }); @@ -63,7 +62,6 @@ test("create a service with a on stop method", async () => { props: { sourceCodeFile: expect.any(String), environmentVariables: {}, - autoStart: true, }, type: cloud.SERVICE_FQN, }); @@ -76,8 +74,8 @@ test("create a service with a on stop method", async () => { .filter((v) => v.sourceType == cloud.SERVICE_FQN) .map((trace) => trace.data.message) ).toEqual([ - "start!", "root/my_service started", + "start!", "stop!", "root/my_service stopped", ]); @@ -106,7 +104,6 @@ test("create a service without autostart", async () => { props: { sourceCodeFile: expect.any(String), environmentVariables: {}, - autoStart: false, }, type: cloud.SERVICE_FQN, }); diff --git a/libs/wingsdk/test/target-sim/topic-producer.test.ts b/libs/wingsdk/test/target-sim/topic-producer.test.ts index 168ee5e95e7..afe43c76cb4 100644 --- a/libs/wingsdk/test/target-sim/topic-producer.test.ts +++ b/libs/wingsdk/test/target-sim/topic-producer.test.ts @@ -1,6 +1,6 @@ import { Construct } from "constructs"; import { test, expect } from "vitest"; -import { listMessages } from "./util"; +import { listMessages, waitUntilTraceCount } from "./util"; import * as cloud from "../../src/cloud"; import { Testing } from "../../src/simulator"; import { SimApp } from "../sim-app"; @@ -27,6 +27,7 @@ test("publishing messages to topic", async () => { const processor = Testing.makeHandler(`async handle(event) { if (event.message === "") throw new Error("No message recieved"); + console.log("Message received"); }`); topic.onMessage(processor); } @@ -44,6 +45,10 @@ test("publishing messages to topic", async () => { // WHEN await publisher.invoke("ABC"); + await waitUntilTraceCount(s, 1, (trace) => + trace.data.message.includes("Message received") + ); + // THEN await s.stop(); diff --git a/libs/wingsdk/test/target-sim/util.ts b/libs/wingsdk/test/target-sim/util.ts index de8c41ed6fb..07aab70729f 100644 --- a/libs/wingsdk/test/target-sim/util.ts +++ b/libs/wingsdk/test/target-sim/util.ts @@ -29,7 +29,7 @@ export interface IScopeCallback { (scope: Construct): void; } -export function listMessages(s: Simulator) { +export function listMessages(s: Simulator): string[] { const message = s.listTraces().map((trace) => trace.data.message); // Redact any messages containing port numbers return message.map((m) => diff --git a/libs/wingsdk/test/ui/__snapshots__/ui.test.ts.snap b/libs/wingsdk/test/ui/__snapshots__/ui.test.ts.snap index 013056fac0d..8fb72eef1b3 100644 --- a/libs/wingsdk/test/ui/__snapshots__/ui.test.ts.snap +++ b/libs/wingsdk/test/ui/__snapshots__/ui.test.ts.snap @@ -3,10 +3,14 @@ exports[`can obtain ui components 1`] = ` [ "root/MyClass/Button/Handler started", + "root/MyClass/Button/Handler/Policy started", "root/MyClass/Field/Handler started", + "root/MyClass/Field/Handler/Policy started", "Invoke (payload="").", "Invoke (payload="").", + "root/MyClass/Button/Handler/Policy stopped", "root/MyClass/Button/Handler stopped", + "root/MyClass/Field/Handler/Policy stopped", "root/MyClass/Field/Handler stopped", ] `; diff --git a/tools/hangar/__snapshots__/invalid.ts.snap b/tools/hangar/__snapshots__/invalid.ts.snap index a44e6108b80..72cf9c4ddd0 100644 --- a/tools/hangar/__snapshots__/invalid.ts.snap +++ b/tools/hangar/__snapshots__/invalid.ts.snap @@ -3558,6 +3558,32 @@ Test Files 1 failed (1) Duration " `; +exports[`simulator_permissions.test.w 1`] = ` +"fail ┌ simulator_permissions.test.wsim » root/env0/test:incorrect resource permission + │ Error: Resource \\"root/env0/test:incorrect resource permission/Handler\\" does not have permission to perform operation \\"put\\" on resource \\"root/env0/b1\\". + │ --> ../../../examples/tests/invalid/simulator_permissions.test.w:15:3 + │ | while i > 0 { + │ | i -= 1; + │ | } + │ 15 | buckets.at(i).put(\\"key\\", \\"value\\"); + │ | ^ + └ at /simulator_permissions.test.w:15:3 +fail ┌ simulator_permissions.test.wsim » root/env1/test:incorrect permission operation + │ Error: Resource \\"root/env1/test:incorrect permission operation/Handler\\" does not have permission to perform operation \\"put\\" on resource \\"root/env1/b1\\". + │ --> ../../../examples/tests/invalid/simulator_permissions.test.w:25:3 + │ | while i > 0 { + │ | i -= 1; + │ | } + │ 25 | buckets.at(i).put(\\"key\\", \\"value\\"); + │ | ^ + └ at /simulator_permissions.test.w:25:3 + + +Tests 2 failed (2) +Test Files 1 failed (1) +Duration " +`; + exports[`sorted_errors_no_span.test.w 1`] = ` "error: Expected type to be \\"num\\", but got \\"str\\" instead --> ../../../examples/tests/invalid/sorted_errors_no_span.test.w:1:14