You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 7-8.RSVP
Socket
Socket
Sign inDemoInstall

@pulumi/pulumi

Package Overview
Dependencies
Maintainers
2
Versions
4281
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.118.0 to 3.118.1-alpha.x0ebfde2

159

automation/events.d.ts
import { OpMap, OpType } from "./stack";
/**
* CancelEvent is emitted when the user initiates a cancellation of the update in progress, or
* the update successfully completes.
*/
export declare type CancelEvent = {};
/**
* StdoutEngineEvent is emitted whenever a generic message is written, for example warnings
* from the pulumi CLI itself. Less common than DiagnosticEvent
*/
export interface StdoutEngineEvent {

@@ -7,2 +15,6 @@ message: string;

}
/**
* DiagnosticEvent is emitted whenever a diagnostic message is provided, for example errors from
* a cloud resource provider while trying to create or update a resource.
*/
export interface DiagnosticEvent {

@@ -17,2 +29,5 @@ urn?: string;

}
/**
* PolicyEvent is emitted whenever there is a Policy violation.
*/
export interface PolicyEvent {

@@ -28,49 +43,169 @@ resourceUrn?: string;

}
/**
* PreludeEvent is emitted at the start of an update.
*/
export interface PreludeEvent {
/**
* config contains the keys and values for the update.
* Encrypted configuration values may be blinded.
*/
config: Record<string, string>;
}
/**
* SummaryEvent is emitted at the end of an update, with a summary of the changes made.
*/
export interface SummaryEvent {
/**
* maybeCorrupt is set if one or more of the resources is in an invalid state.
*/
maybeCorrupt: boolean;
/**
* duration is the number of seconds the update was executing.
*/
durationSeconds: number;
/**
* resourceChanges contains the count for resource change by type. The keys are deploy.StepOp,
* which is not exported in this package.
*/
resourceChanges: OpMap;
/**
* policyPacks run during update. Maps PolicyPackName -> version.
* Note: When this field was initially added, we forgot to add the JSON tag
* and are now locked into using PascalCase for this field to maintain backwards
* compatibility. For older clients this will map to the version, while for newer ones
* it will be the version tag prepended with "v".
*/
policyPacks: Record<string, string>;
}
export declare enum DiffKind {
/**
* add indicates that the property was added.
*/
add = "add",
/**
* addReplace indicates that the property was added and requires that the resource be replaced.
*/
addReplace = "add-replace",
/**
* delete indicates that the property was deleted.
*/
delete = "delete",
/**
* deleteReplace indicates that the property was deleted and requires that the resource be replaced.
*/
deleteReplace = "delete-replace",
/**
* update indicates that the property was updated.
*/
update = "update",
/**
* updateReplace indicates that the property was updated and requires that the resource be replaced.
*/
updateReplace = "update-replace"
}
/**
* PropertyDiff describes the difference between a single property's old and new values.
*/
export interface PropertyDiff {
/**
* diffKind is the kind of difference.
*/
diffKind: DiffKind;
/**
* inputDiff is true if this is a difference between old and new inputs rather than old state and new inputs.
*/
inputDiff: boolean;
}
/**
* StepEventMetadata describes a "step" within the Pulumi engine, which is any concrete action
* to migrate a set of cloud resources from one state to another.
*/
export interface StepEventMetadata {
/**
* Op is the operation being performed.
*/
op: OpType;
urn: string;
type: string;
/**
* Old is the state of the resource before performing the step.
*/
old?: StepEventStateMetadata;
/**
* New is the state of the resource after performing the step.
*/
new?: StepEventStateMetadata;
/**
* Keys causing a replacement (only applicable for "create" and "replace" Ops).
*/
keys?: string[];
/**
* Keys that changed with this step.
*/
diffs?: string[];
/**
* The diff for this step as a list of property paths and difference types.
*/
detailedDiff?: Record<string, PropertyDiff>;
/**
* Logical is set if the step is a logical operation in the program.
*/
logical?: boolean;
/**
* Provider actually performing the step.
*/
provider: string;
}
/**
* StepEventStateMetadata is the more detailed state information for a resource as it relates to
* a step(s) being performed.
*/
export interface StepEventStateMetadata {
type: string;
urn: string;
/**
* Custom indicates if the resource is managed by a plugin.
*/
custom?: boolean;
/**
* Delete is true when the resource is pending deletion due to a replacement.
*/
delete?: boolean;
/**
* ID is the resource's unique ID, assigned by the resource provider (or blank if none/uncreated).
*/
id: string;
/**
* Parent is an optional parent URN that this resource belongs to.
*/
parent: string;
/**
* Protect is true to "protect" this resource (protected resources cannot be deleted).
*/
protect?: boolean;
/**
* RetainOnDelete is true if the resource is not physically deleted when it is logically deleted.
*/
retainOnDelete?: boolean;
/**
* Inputs contains the resource's input properties (as specified by the program). Secrets have
* filtered out, and large assets have been replaced by hashes as applicable.
*/
inputs: Record<string, any>;
/**
* Outputs contains the resource's complete output state (as returned by the resource provider).
*/
outputs: Record<string, any>;
/**
* Provider is the resource's provider reference
*/
provider: string;
/**
* InitErrors is the set of errors encountered in the process of initializing resource.
*/
initErrors?: string[];
}
/**
* ResourcePreEvent is emitted before a resource is modified.
*/
export interface ResourcePreEvent {

@@ -80,2 +215,5 @@ metadata: StepEventMetadata;

}
/**
* ResOutputsEvent is emitted when a resource is finished being provisioned.
*/
export interface ResOutputsEvent {

@@ -85,2 +223,6 @@ metadata: StepEventMetadata;

}
/**
* ResOpFailedEvent is emitted when a resource operation fails. Typically a DiagnosticEvent is
* emitted before this event, indicating the root cause of the error.
*/
export interface ResOpFailedEvent {

@@ -91,4 +233,21 @@ metadata: StepEventMetadata;

}
/**
* EngineEvent describes a Pulumi engine event, such as a change to a resource or diagnostic
* message. EngineEvent is a discriminated union of all possible event types, and exactly one
* field will be non-nil.
*/
export interface EngineEvent {
/**
* Sequence is a unique, and monotonically increasing number for each engine event sent to the
* Pulumi Service. Since events may be sent concurrently, and/or delayed via network routing,
* the sequence number is to ensure events can be placed into a total ordering.
*
* - No two events can have the same sequence number.
* - Events with a lower sequence number must have been emitted before those with a higher
* sequence number.
*/
sequence: number;
/**
* Timestamp is a Unix timestamp (seconds) of when the event was emitted.
*/
timestamp: number;

@@ -95,0 +254,0 @@ cancelEvent?: CancelEvent;

24

automation/events.js

@@ -18,15 +18,27 @@ "use strict";

(function (DiffKind) {
// add indicates that the property was added.
/**
* add indicates that the property was added.
*/
DiffKind["add"] = "add";
// addReplace indicates that the property was added and requires that the resource be replaced.
/**
* addReplace indicates that the property was added and requires that the resource be replaced.
*/
DiffKind["addReplace"] = "add-replace";
// delete indicates that the property was deleted.
/**
* delete indicates that the property was deleted.
*/
DiffKind["delete"] = "delete";
// deleteReplace indicates that the property was deleted and requires that the resource be replaced.
/**
* deleteReplace indicates that the property was deleted and requires that the resource be replaced.
*/
DiffKind["deleteReplace"] = "delete-replace";
// update indicates that the property was updated.
/**
* update indicates that the property was updated.
*/
DiffKind["update"] = "update";
// updateReplace indicates that the property was updated and requires that the resource be replaced.
/**
* updateReplace indicates that the property was updated and requires that the resource be replaced.
*/
DiffKind["updateReplace"] = "update-replace";
})(DiffKind = exports.DiffKind || (exports.DiffKind = {}));
//# sourceMappingURL=events.js.map

@@ -320,6 +320,8 @@ import { PulumiCommand } from "./cmd";

/**
* Returns all Stacks created under the current Project.
* Returns all Stacks from the underlying backend based on the provided options.
* This queries underlying backend and may return stacks not present in the Workspace (as Pulumi.<stack>.yaml files).
*
* @param opts Options to customize the behavior of the list.
*/
listStacks(): Promise<StackSummary[]>;
listStacks(opts?: ListOptions): Promise<StackSummary[]>;
/**

@@ -458,1 +460,7 @@ * Installs a plugin in the Workspace, for example to use cloud providers like AWS or GCP.

}
export interface ListOptions {
/**
* List all stacks instead of just stacks for the current project
*/
all?: boolean;
}

@@ -630,8 +630,16 @@ "use strict";

/**
* Returns all Stacks created under the current Project.
* Returns all Stacks from the underlying backend based on the provided options.
* This queries underlying backend and may return stacks not present in the Workspace (as Pulumi.<stack>.yaml files).
*
* @param opts Options to customize the behavior of the list.
*/
listStacks() {
listStacks(opts) {
return __awaiter(this, void 0, void 0, function* () {
const result = yield this.runPulumiCmd(["stack", "ls", "--json"]);
const args = ["stack", "ls", "--json"];
if (opts) {
if (opts.all) {
args.push("--all");
}
}
const result = yield this.runPulumiCmd(args);
return JSON.parse(result.stdout);

@@ -638,0 +646,0 @@ });

import { PulumiCommand } from "./cmd";
import { ConfigMap, ConfigValue } from "./config";
import { ListOptions } from "./localWorkspace";
import { ProjectSettings } from "./projectSettings";

@@ -218,6 +219,8 @@ import { OutputMap } from "./stack";

/**
* Returns all Stacks created under the current Project.
* This queries underlying backend and may return stacks not present in the Workspace (as Pulumi.<stack>.yaml files).
* Returns all Stacks from the underlying backend based on the provided options.
* This queries backend and may return stacks not present in the Workspace (as Pulumi.<stack>.yaml files).
*
* @param opts Options to customize the behavior of the list.
*/
listStacks(): Promise<StackSummary[]>;
listStacks(opts?: ListOptions): Promise<StackSummary[]>;
/**

@@ -224,0 +227,0 @@ * Installs a plugin in the Workspace, for example to use cloud providers like AWS or GCP.

@@ -30,2 +30,5 @@ import { Resource } from "./resource";

export declare function unsecret<T>(val: Output<T>): Output<T>;
/**
* [isSecret] returns `true` if and only if the provided [Output] is a secret.
*/
export declare function isSecret<T>(val: Output<T>): Promise<boolean>;

@@ -32,0 +35,0 @@ /**

@@ -269,7 +269,11 @@ "use strict";

}
// Returns an promise denoting if the output is a secret or not. This is not the same as just calling `.isSecret`
// because in cases where the output does not have a `isSecret` property and it is a Proxy, we need to ignore
// the isSecret member that the proxy reports back.
// This calls the public implementation so that we only make any calculations in a single place.
/** @internal */
/**
* Returns a promise denoting if the output is a secret or not. This is not the same as just calling `.isSecret`
* because in cases where the output does not have a `isSecret` property and it is a Proxy, we need to ignore
* the isSecret member that the proxy reports back.
*
* This calls the public implementation so that we only make any calculations in a single place.
*
* @internal
*/
function isSecretOutput(o) {

@@ -279,16 +283,18 @@ return isSecret(o);

exports.isSecretOutput = isSecretOutput;
// Helper function for `output`. This function trivially recurses through an object, copying it,
// while also lifting any inner Outputs (with all their respective state) to a top-level Output at
// the end. If there are no inner outputs, this will not affect the data (except by producing a new
// copy of it).
//
// Importantly:
//
// 1. Resources encountered while recursing are not touched. This helps ensure they stay Resources
// (with an appropriate prototype chain).
// 2. Primitive values (string, number, etc.) are returned as is.
// 3. Arrays and Record are recursed into. An Array<...> that contains any Outputs wil become an
// Output<Array<Unwrapped>>. A Record<string, ...> that contains any Output values will be an
// Output<Record<string, Unwrap<...>>. In both cases of recursion, the outer Output's
// known/secret/resources will be computed from the nested Outputs.
/**
* Helper function for `output`. This function trivially recurses through an object, copying it,
* while also lifting any inner Outputs (with all their respective state) to a top-level Output at
* the end. If there are no inner outputs, this will not affect the data (except by producing a new
* copy of it).
*
* Importantly:
*
* 1. Resources encountered while recursing are not touched. This helps ensure they stay Resources
* (with an appropriate prototype chain).
* 2. Primitive values (string, number, etc.) are returned as is.
* 3. Arrays and Record are recursed into. An Array<...> that contains any Outputs wil become an
* Output<Array<Unwrapped>>. A Record<string, ...> that contains any Output values will be an
* Output<Record<string, Unwrap<...>>. In both cases of recursion, the outer Output's
* known/secret/resources will be computed from the nested Outputs.
*/
function outputRec(val) {

@@ -396,2 +402,5 @@ if (val === null || typeof val !== "object") {

exports.unsecret = unsecret;
/**
* [isSecret] returns `true` if and only if the provided [Output] is a secret.
*/
function isSecret(val) {

@@ -398,0 +407,0 @@ return exports.Output.isInstance(val.isSecret) ? Promise.resolve(false) : val.isSecret;

{
"name": "@pulumi/pulumi",
"version": "3.118.0",
"version": "3.118.1-alpha.x0ebfde2",
"description": "Pulumi's Node.js SDK",

@@ -5,0 +5,0 @@ "license": "Apache-2.0",

@@ -9,2 +9,8 @@ import { Input, Inputs, Output } from "./output";

export declare function createUrn(name: Input<string>, type: Input<string>, parent?: Resource | Input<URN>, project?: string, stack?: string): Output<string>;
/**
* allAliases computes the full set of aliases for a child resource given a set of aliases applied to the child and
* parent resources. This includes the child resource's own aliases, as well as aliases inherited from the parent.
* If there are N child aliases, and M parent aliases, there will be (M+1)*(N+1)-1 total aliases,
* or, as calculated in the logic below, N+(M*(1+N)).
*/
export declare function allAliases(childAliases: Input<URN | Alias>[], childName: string, childType: string, parent: Resource, parentName: string): Output<URN>[];

@@ -25,3 +31,28 @@ /**

static isInstance(obj: any): obj is Resource;
/**
* sourcePosition returns the source position of the user code that instantiated this resource.
*
* This is somewhat brittle in that it expects a call stack of the form:
* - Resource class constructor
* - abstract Resource subclass constructor
* - concrete Resource subclass constructor
* - user code
*
* This stack reflects the expected class hierarchy of "cloud resource / component resource < customresource/componentresource < resource".
*
* For example, consider the AWS S3 Bucket resource. When user code instantiates a Bucket, the stack will look like
* this:
*
* new Resource (/path/to/resource.ts:123:45)
* new CustomResource (/path/to/resource.ts:678:90)
* new Bucket (/path/to/bucket.ts:987:65)
* <user code> (/path/to/index.ts:4:3)
*
* Because Node can only give us the stack trace as text, we parse out the source position using a regex that
* matches traces of this form (see stackTraceRegExp above).
*/
private static sourcePosition;
/**
* Returns the provider for the given module member, if one exists.
*/
getProvider(moduleMember: string): ProviderResource | undefined;

@@ -28,0 +59,0 @@ /**

@@ -70,5 +70,7 @@ "use strict";

exports.createUrn = createUrn;
// inheritedChildAlias computes the alias that should be applied to a child based on an alias applied to it's parent.
// This may involve changing the name of the resource in cases where the resource has a named derived from the name of
// the parent, and the parent name changed.
/**
* inheritedChildAlias computes the alias that should be applied to a child based on an alias applied to it's parent.
* This may involve changing the name of the resource in cases where the resource has a named derived from the name of
* the parent, and the parent name changed.
*/
function inheritedChildAlias(childName, parentName, parentAlias, childType) {

@@ -96,3 +98,5 @@ // If the child name has the parent name as a prefix, then we make the assumption that it was

}
// Extract the type and name parts of a URN
/**
* Extracts the type and name from a URN.
*/
function urnTypeAndName(urn) {

@@ -106,5 +110,8 @@ const parts = urn.split("::");

}
// Make a copy of the aliases array, and add to it any implicit aliases inherited from its parent.
// If there are N child aliases, and M parent aliases, there will be (M+1)*(N+1)-1 total aliases,
// or, as calculated in the logic below, N+(M*(1+N)).
/**
* allAliases computes the full set of aliases for a child resource given a set of aliases applied to the child and
* parent resources. This includes the child resource's own aliases, as well as aliases inherited from the parent.
* If there are N child aliases, and M parent aliases, there will be (M+1)*(N+1)-1 total aliases,
* or, as calculated in the logic below, N+(M*(1+N)).
*/
function allAliases(childAliases, childName, childType, parent, parentName) {

@@ -271,22 +278,24 @@ const aliases = [];

}
// sourcePosition returns the source position of the user code that instantiated this resource.
//
// This is somewhat brittle in that it expects a call stack of the form:
// - Resource class constructor
// - abstract Resource subclass constructor
// - concrete Resource subclass constructor
// - user code
//
// This stack reflects the expected class hierarchy of "cloud resource / component resource < customresource/componentresource < resource".
//
// For example, consider the AWS S3 Bucket resource. When user code instantiates a Bucket, the stack will look like
// this:
//
// new Resource (/path/to/resource.ts:123:45)
// new CustomResource (/path/to/resource.ts:678:90)
// new Bucket (/path/to/bucket.ts:987:65)
// <user code> (/path/to/index.ts:4:3)
//
// Because Node can only give us the stack trace as text, we parse out the source position using a regex that
// matches traces of this form (see stackTraceRegExp above).
/**
* sourcePosition returns the source position of the user code that instantiated this resource.
*
* This is somewhat brittle in that it expects a call stack of the form:
* - Resource class constructor
* - abstract Resource subclass constructor
* - concrete Resource subclass constructor
* - user code
*
* This stack reflects the expected class hierarchy of "cloud resource / component resource < customresource/componentresource < resource".
*
* For example, consider the AWS S3 Bucket resource. When user code instantiates a Bucket, the stack will look like
* this:
*
* new Resource (/path/to/resource.ts:123:45)
* new CustomResource (/path/to/resource.ts:678:90)
* new Bucket (/path/to/bucket.ts:987:65)
* <user code> (/path/to/index.ts:4:3)
*
* Because Node can only give us the stack trace as text, we parse out the source position using a regex that
* matches traces of this form (see stackTraceRegExp above).
*/
static sourcePosition() {

@@ -315,3 +324,5 @@ var _a;

}
// getProvider fetches the provider for the given module member, if any.
/**
* Returns the provider for the given module member, if one exists.
*/
getProvider(moduleMember) {

@@ -360,3 +371,6 @@ const pkg = resource_1.pkgFromType(moduleMember);

exports.rootStackResource = undefined;
// collapseAliasToUrn turns an Alias into a URN given a set of default data
/**
* Converts an alias into a URN given a set of default data for the missing
* values.
*/
function collapseAliasToUrn(alias, defaultName, defaultType, defaultParent) {

@@ -363,0 +377,0 @@ return output_1.output(alias).apply((a) => {

@@ -146,2 +146,100 @@ "use strict";

});
describe("ListStack Methods", () => __awaiter(void 0, void 0, void 0, function* () {
describe("ListStacks", () => __awaiter(void 0, void 0, void 0, function* () {
const stackJson = `[
{
"name": "testorg1/testproj1/teststack1",
"current": false,
"url": "https://app.pulumi.com/testorg1/testproj1/teststack1"
},
{
"name": "testorg1/testproj1/teststack2",
"current": false,
"url": "https://app.pulumi.com/testorg1/testproj1/teststack2"
}
]`;
it(`should handle stacks correctly for listStacks`, () => __awaiter(void 0, void 0, void 0, function* () {
const mockWithReturnedStacks = {
command: "pulumi",
version: null,
run: (args, cwd, additionalEnv) => __awaiter(void 0, void 0, void 0, function* () {
return new automation_1.CommandResult(stackJson, "", 0);
}),
};
const workspace = yield automation_1.LocalWorkspace.create({ pulumiCommand: mockWithReturnedStacks });
const stacks = yield workspace.listStacks();
assert_1.default.strictEqual(stacks.length, 2);
assert_1.default.strictEqual(stacks[0].name, "testorg1/testproj1/teststack1");
assert_1.default.strictEqual(stacks[0].current, false);
assert_1.default.strictEqual(stacks[0].url, "https://app.pulumi.com/testorg1/testproj1/teststack1");
assert_1.default.strictEqual(stacks[1].name, "testorg1/testproj1/teststack2");
assert_1.default.strictEqual(stacks[1].current, false);
assert_1.default.strictEqual(stacks[1].url, "https://app.pulumi.com/testorg1/testproj1/teststack2");
}));
it(`should use correct args for listStacks`, () => __awaiter(void 0, void 0, void 0, function* () {
let capturedArgs = [];
const mockPulumiCommand = {
command: "pulumi",
version: null,
run: (args, cwd, additionalEnv) => __awaiter(void 0, void 0, void 0, function* () {
capturedArgs = args;
return new automation_1.CommandResult(stackJson, "", 0);
}),
};
const workspace = yield automation_1.LocalWorkspace.create({
pulumiCommand: mockPulumiCommand,
});
yield workspace.listStacks();
assert_1.default.deepStrictEqual(capturedArgs, ["stack", "ls", "--json"]);
}));
}));
describe("ListStacks with all", () => __awaiter(void 0, void 0, void 0, function* () {
const stackJson = `[
{
"name": "testorg1/testproj1/teststack1",
"current": false,
"url": "https://app.pulumi.com/testorg1/testproj1/teststack1"
},
{
"name": "testorg1/testproj2/teststack2",
"current": false,
"url": "https://app.pulumi.com/testorg1/testproj2/teststack2"
}
]`;
it(`should handle stacks correctly for listStacks when all is set`, () => __awaiter(void 0, void 0, void 0, function* () {
const mockWithReturnedStacks = {
command: "pulumi",
version: null,
run: () => __awaiter(void 0, void 0, void 0, function* () { return new automation_1.CommandResult(stackJson, "", 0); }),
};
const workspace = yield automation_1.LocalWorkspace.create({
pulumiCommand: mockWithReturnedStacks,
});
const stacks = yield workspace.listStacks({ all: true });
assert_1.default.strictEqual(stacks.length, 2);
assert_1.default.strictEqual(stacks[0].name, "testorg1/testproj1/teststack1");
assert_1.default.strictEqual(stacks[0].current, false);
assert_1.default.strictEqual(stacks[0].url, "https://app.pulumi.com/testorg1/testproj1/teststack1");
assert_1.default.strictEqual(stacks[1].name, "testorg1/testproj2/teststack2");
assert_1.default.strictEqual(stacks[1].current, false);
assert_1.default.strictEqual(stacks[1].url, "https://app.pulumi.com/testorg1/testproj2/teststack2");
}));
it(`should use correct args for listStacks when all is set`, () => __awaiter(void 0, void 0, void 0, function* () {
let capturedArgs = [];
const mockPuluiCommand = {
command: "pulumi",
version: null,
run: (args, cwd, additionalEnv) => __awaiter(void 0, void 0, void 0, function* () {
capturedArgs = args;
return new automation_1.CommandResult(stackJson, "", 0);
}),
};
const workspace = yield automation_1.LocalWorkspace.create({
pulumiCommand: mockPuluiCommand,
});
yield workspace.listStacks({ all: true });
assert_1.default.deepStrictEqual(capturedArgs, ["stack", "ls", "--json", "--all"]);
}));
}));
}));
it(`Environment functions`, function () {

@@ -148,0 +246,0 @@ return __awaiter(this, void 0, void 0, function* () {

@@ -57,3 +57,7 @@ "use strict";

// Workaround errors we sometimes get on some machines saying that Object.values is not available.
/** @internal */
/**
* A polyfill for Object.values
*
* @internal
*/
function values(obj) {

@@ -60,0 +64,0 @@ const result = [];

@@ -1,1 +0,1 @@

export declare const version = "3.118.0";
export declare const version = "3.118.1";

@@ -16,3 +16,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.version = "3.118.0";
exports.version = "3.118.1-alpha.x0ebfde2";
//# sourceMappingURL=version.js.map

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc