How to pass Pulumi's Output<T> to the container definition of a task within ecs? - json

A containerDefinition within a Task Definition needs to be provided as a single valid JSON document. I'm creating a generic ECS service that should handle dynamic data. Here is the code:
genericClientService(environment: string, targetGroupArn: Output<string>) {
return new aws.ecs.Service(`${this.domainName}-client-service-${environment}`, {
cluster: this.clientCluster.id,
taskDefinition: new aws.ecs.TaskDefinition(`${this.domainName}-client-${environment}`, {
family: `${this.domainName}-client-${environment}`,
containerDefinitions: JSON.stringify(
clientTemplate(
this.defaultRegion,
this.domainName,
this.taskEnvVars?.filter((object: { ENVIRONMENT: string }) => object.ENVIRONMENT === environment),
this.ecrRepositories
)
),
cpu: "256",
executionRoleArn: taskDefinitionRole.arn,
memory: "512",
networkMode: "awsvpc",
requiresCompatibilities: ["FARGATE"],
}).arn,
desiredCount: 1,
...
There is a need of information from an already built resource this.ecrRepositories which represents a list of ECR repositories needed. The problem here is that let's say you want to retrieve the repository URL and apply the necessary 'apply()' method, it will return an Output<string>. This would be fine normally, but since containerDefinitions needs to be a valid JSON document, Pulumi can't handle it since JSON on an Output<T> is not supported;
Calling [toJSON] on an [Output<T>] is not supported. To get the value of an Output as a JSON value or JSON string consider either: 1: o.apply(v => v.toJSON()) 2: o.apply(v => JSON.stringify(v)) See https://pulumi.io/help/outputs for more details. This function may throw in a future version of #pulumi/pulumi.
Blockquote
Neither of the suggested considerations above will work as the dynamicly passed variables are wrapped within a toJSON function callback. Because of this it won't matter how you pass resource information since it will always be an Output<T>.
Is there a way how to deal with this issue?

Assuming clientTemplate works correctly and the error happens in the snippet that you shared, you should be able to solve it with
containerDefinitions: pulumi.all(
clientTemplate(
this.defaultRegion,
this.domainName,
this.taskEnvVars?.filter((object: { ENVIRONMENT: string }) => object.ENVIRONMENT === environment),
this.ecrRepositories
)).apply(JSON.stringify),

Related

Storing a Json value Security Threads using wordpress plugin

I'm performing an audit against OASP best practices, my goal is to identify all major security threads happening when I send the data from the frontend until it is saved in the database.
Context.
Json Data: It's a tree that grows/decreases according to the UI action, the JSON is formatting for a frontend function.
Frontend: custom UI, it generates a list of team members in a JS object and appends/removes from it, the data input is not stored in any HTML elements to prevent XSS, however not sure if there is any potential XSS in the code:
Function to create the element:
const newTeam = {
name,
emoji,
parent_id: parentTeamId,
children: [],
};
const newTree = insertTeam( newTeam );
Function to add the element to the nested groups:
export function insertTeam( team, root = tree ) {
if ( root.id === team.parent_id ) {
return {
...root,
children: [
...root.children,
{
...team,
// Using a simple time based ID for now.
id: `${ root.id }-${ Date.now() }`,
},
],
};
}
return {
...root,
children: root.children.map( ( childTree ) =>
insertTeam( team, childTree )
),
};
}
the data is stored in a hidden field in a form, the final format looks like this:
Var_Dump
string(756) "{\"id\":1,\"name\":\"MyCustomGroup.\",\"emoji\":\"šŸ•\",\"parent_id\":null,\"children\":[{\"id\":2,\"name\":\"Food\",\"emoji\":\"šŸ„©\",\"parent_id\":1,\"children\":[]},{\"id\":3,\"name\":\"Canine Therapy\",\"emoji\":\"šŸ˜Œ\",\"parent_id\":1,\"children\":[{\"id\":5,\"name\":\"Games\",\"emoji\":\"šŸŽ¾\",\"parent_id\":3,\"children\":[{\"name\":\"rocket\",\"emoji\":\"šŸš€\",\"parent_id\":5,\"id\":\"5-1632455609334\",\"children\":[]}]}]},{\"name\":\"frog\",\"emoji\":\"šŸø\",\"parent_id\":1,\"id\":\"1-1632456503102\",\"children\":[]},{\"name\":\"bear\",\"emoji\":\"šŸ»\",\"parent_id\":1,\"id\":\"1-1632456578430\",\"children\":[{\"name\":\"a\",\"emoji\":\"a\",\"parent_id\":\"1-1632456578430\",\"children\":[],\"id\":\"1-1632456578430-1632665530415\"}]}]}"
The backend: The backend is a Wordpress plugin, to insert the data I'm using $wpdb->insert process the string passed and for cleanup / sanitize I'm using:
wp_kses( $obj, array() )
I'm not an expert in security, but I can detect threads for XSS attacks, what else I'm missing? Also if you guys have some recommendations are welcome. Thanks.
OWASP security standards, as its name suggests, are only a compilation of standards security checks for web applications. In fact, the npm audit command check for outdated dependencies or known issues. That command doesn't accomplish an audit on the fly. Security issues are raised from several sources, like Node
I think you should try something like sonarqube
it's a great test tool and you can start from there

How to convert Pulumi Output<t> to string?

I am dealing with creating AWS API Gateway. I am trying to create CloudWatch Log group and name it API-Gateway-Execution-Logs_${restApiId}/${stageName}. I have no problem in Rest API creation.
My issue is in converting restApi.id which is of type pulumi.Outout to string.
I have tried these 2 versions which are proposed in their PR#2496
const restApiId = apiGatewayToSqsQueueRestApi.id.apply((v) => `${v}`);
const restApiId = pulumi.interpolate `${apiGatewayToSqsQueueRestApi.id}`
here is the code where it is used
const cloudWatchLogGroup = new aws.cloudwatch.LogGroup(
`API-Gateway-Execution-Logs_${restApiId}/${stageName}`,
{},
);
stageName is just a string.
I have also tried to apply again like
const restApiIdStrign = restApiId.apply((v) => v);
I always got this error from pulumi up
aws:cloudwatch:LogGroup API-Gateway-Execution-Logs_Calling [toString] on an [Output<T>] is not supported.
Please help me convert Output to string
#Cameron answered the naming question, I want to answer your question in the title.
It's not possible to convert an Output<string> to string, or any Output<T> to T.
Output<T> is a container for a future value T which may not be resolved even after the program execution is over. Maybe, your restApiId is generated by AWS at deployment time, so if you run your program in preview, there's no value for restApiId.
Output<T> is like a Promise<T> which will be eventually resolved, potentially after some resources are created in the cloud.
Therefore, the only operations with Output<T> are:
Convert it to another Output<U> with apply(f), where f: T -> U
Assign it to an Input<T> to pass it to another resource constructor
Export it from the stack
Any value manipulation has to happen within an apply call.
So long as the Output is resolvable while the Pulumi script is still running, you can use an approach like the below:
import {Output} from "#pulumi/pulumi";
import * as fs from "fs";
// create a GCP registry
const registry = new gcp.container.Registry("my-registry");
const registryUrl = registry.id.apply(_=>gcp.container.getRegistryRepository().then(reg=>reg.repositoryUrl));
// create a GCP storage bucket
const bucket = new gcp.storage.Bucket("my-bucket");
const bucketURL = bucket.url;
function GetValue<T>(output: Output<T>) {
return new Promise<T>((resolve, reject)=>{
output.apply(value=>{
resolve(value);
});
});
}
(async()=>{
fs.writeFileSync("./PulumiOutput_Public.json", JSON.stringify({
registryURL: await GetValue(registryUrl),
bucketURL: await GetValue(bucketURL),
}, null, "\t"));
})();
To clarify, this approach only works when you're doing an actual deployment (ie. pulumi up), not merely a preview. (as explained here)
That's good enough for my use-case though, as I just want a way to store the registry-url and such after each deployment, for other scripts in my project to know where to find the latest version.
Short Answer
You can specify the physical name of your LogGroup by specifying the name input and you can construct this from the API Gateway id output using pulumi.interpolate. You must use a static string as the first argument to your resource. I would recommend using the same name you're providing to your API Gateway resource as the name for your Log Group. Here's an example:
const apiGatewayToSqsQueueRestApi = new aws.apigateway.RestApi("API-Gateway-Execution");
const cloudWatchLogGroup = new aws.cloudwatch.LogGroup(
"API-Gateway-Execution", // this is the logical name and must be a static string
{
name: pulumi.interpolate`API-Gateway-Execution-Logs_${apiGatewayToSqsQueueRestApi.id}/${stageName}` // this the physical name and can be constructed from other resource outputs
},
);
Longer Answer
The first argument to every resource type in Pulumi is the logical name and is used for Pulumi to track the resource internally from one deployment to the next. By default, Pulumi auto-names the physical resources from this logical name. You can override this behavior by specifying your own physical name, typically via a name input to the resource. More information on resource names and auto-naming is here.
The specific issue here is that logical names cannot be constructed from other resource outputs. They must be static strings. Resource inputs (such as name) can be constructed from other resource outputs.
Encountered a similar issue recently. Adding this for anyone that comes looking.
For pulumi python, some policies requires the input to be stringified json. Say you're writing an sqs queue and a dlq for it, you may initially write something like this:
import pulumi_aws
dlq = aws.sqs.Queue()
queue = pulumi_aws.sqs.Queue(
redrive_policy=json.dumps({
"deadLetterTargetArn": dlq.arn,
"maxReceiveCount": "3"
})
)
The issue we see here is that the json lib errors out stating type Output cannot be parsed. When you print() dlq.arn, you'd see a memory address for it like <pulumi.output.Output object at 0x10e074b80>
In order to work around this, we have to leverage the Outputs lib and write a callback function
import pulumi_aws
def render_redrive_policy(arn):
return json.dumps({
"deadLetterTargetArn": arn,
"maxReceiveCount": "3"
})
dlq = pulumi_aws.sqs.Queue()
queue = pulumi_aws.sqs.Queue(
redrive_policy=Output.all(arn=dlq.arn).apply(
lambda args: render_redrive_policy(args["arn"])
)
)

Read values from local.settings.json in VS 2017 Azure Function development

I am writing an Azure function in VS 2017. I need to set up a few custom configuration parameters. I added them in local.settings.json under Values.
{
"IsEncrypted":false,
"Values" : {
"CustomUrl" : "www.google.com",
"Keys": {
"Value1":"1",
"Value2" :"2"
}
}
}
Now, ConfigurationManager.AppSettings["CustomUrl"] returns null.
I'm using:
.NET Framework 4.7
Microsoft.NET.Sdk.Functions 1.0.5
System.Configuration.ConfigurationManager 4.4.0
Azure.Functions.Cli 1.0.4
Am I missing something?
Environment.GetEnvironmentVariable("key")
I was able to read values from local.settings.json using the above line of code.
Firstly, I create a sample and do a test with your local.settings.json data, as Mikhail and ahmelsayed said, it works fine.
Besides, as far as I know, Values collection is expected to be a Dictionary, if it contains any non-string values, it can cause Azure function can not read values from local.settings.json.
My Test:
ConfigurationManager.AppSettings["CustomUrl"] returns null with the following local.settings.json.
{
"IsEncrypted": false,
"Values": {
"CustomUrl": "www.google.com",
"testkey": {
"name": "kname1",
"value": "kval1"
}
}
}
If you are using TimeTrigger based Azure function than you can access your key (created in local.settings.json) from Azure Function as below.
[FunctionName("BackupTableStorageFunction")]
public static void Run([TimerTrigger("%BackUpTableStorageTriggerTime%")]TimerInfo myTimer, TraceWriter log, CancellationToken cancellationToken)
Using .Net 6 (and probably some earlier versions) it is possible to inject IConfiguration into the constructor of the function.
public Function1(IConfiguration configuration)
{
string setting = _configuration.GetValue<string>("MySetting");
}
MySetting must be in the Values section of local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
"MySetting": "value"
}
}
It works with Application settings in Azure Function App as well.
Azure function copies the binaries to the bin folder and runs using the azure function cli, so it searches for the local.settings.json, so make sure you have set the "Copy to Output Directory" to "Copy Always"
Hey you mmight be able to read the properties while debugging, but once you go and try to deploy that in azure, those properties are not going to work anymore. Azure functions does not allow nested properties, you must use all of them inline in the "Values" option or in "ConnectionStrings".
Look at this documentation as reference:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings
var value = Environment.GetEnvironmentVariable("key", EnvironmentVariableTarget.Process); should be the more appropriate answer, though EnvironmentVariableTarget.Process is the default value but it's more meaningful here.
Look at its EnvironmentVariableTarget declaration.
//
// Summary:
// Specifies the location where an environment variable is stored or retrieved in
// a set or get operation.
public enum EnvironmentVariableTarget
{
//
// Summary:
// The environment variable is stored or retrieved from the environment block associated
// with the current process.
Process = 0,
//
// Summary:
// The environment variable is stored or retrieved from the HKEY_CURRENT_USER\Environment
// key in the Windows operating system registry. This value should be used on .NET
// implementations running on Windows systems only.
User = 1,
//
// Summary:
// The environment variable is stored or retrieved from the HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session
// Manager\Environment key in the Windows operating system registry. This value
// should be used on .NET implementations running on Windows systems only.
Machine = 2
}

How to type function's return to be an array of instances of a dynamic class via .phpstorm.meta.php file?

With .phpstorm.meta.php you can overwrite the return type of your class methods. For example:
// .phpstorm.meta.php
namespace PHPSTORM_META
{
$STATIC_METHOD_TYPES = [
\Acme\Node::closest('') => [
"" == "#",
],
];
}
The example above lets PhpStorm understand the return of $node->closest(SomeNodeType::class) is an instance of SomeNodeType.
However, my question is how to make PhpStorm understand that a function returns an array of instances of a given type.
For example:
$node->findAllOfType(SomeNodeType::class) would return an array of SomeNodeType instances (normally one would use SomeNodeType[] if it would not be dynamic).
Attempts to use "#[]" or "#Iterator" instead of "#", in the above code example, failed.
That's simply not supported ... unless you can try and list all possible types manually instead of using single generic rule (which may work in theory -- sorry, have not tried it myself).
https://youtrack.jetbrains.com/issue/WI-27832 -- watch that and related tickets (star/vote/comment) to get notified on any progress.

Deep watch arbitriary JSON keys with computed properties in Ember

I have a use case where a Model has a JSON attribute used for arbitrary configurations: configuration: DS.attr().
I have a configurationService (initialized in every component/route/controller/ā€¦) with computed properties for easily retrieving this configurations throughout the application
Since the JSON configurations are quite large & have variable depth I canā€™t have a computed property for every single one.
Unfortunately, being the Service a singleton computed properties donā€™t detect the changes in the JSON keys (a.k.a. deep watch).
I there a way to force deep watching a JSON attribute?
Example:
services/configuration.js:
// These below can also be computed.alias, same effect
configuration: Ember.computed(ā€˜account.configuration', function() {
// account is set at applicationā€™s route:
// set(this, ā€˜configurationService.account', account);
return this.get(ā€˜account.configurationā€™);
}),
profile: Ember.computed('configuration.profile', function() {
return this.get('configuration.profile');
}),
any/given/component.js:
configurationService: Ember.inject.service(ā€˜configurationā€™),
ā€¦
// These wonā€™t detect changes
randomConfig: Ember.computed.alias(ā€™configurationService.profile.foo.bar.randomConfig')
Considering the configuration object was: {configuration: {profile: {foo: {bar: {randomConfig: false}}}}}, if I somehow change randomConfig to true, it wonā€™t be detected
Note: I considered https://github.com/lytics/ember-data-model-fragments but discarded it since itā€™s too verbose, the issue is that our configuration object can become quite large and deep, dynamic & unpredictable
I tried computed.alias as well with no success.
Any hints or alternatives would be appreciated :)
UPDATE:
I tried with an object Transform (as suggested in Slack) and it doesnā€™t observe it deeply: https://gist.github.com/benoror/272f0ae893f80276ac1553ae048e6b20#file-object-js
You need to transform the plain JS-Object to an Ember-Object, and so for its child objects:
import Ember from 'ember';
import DS from 'ember-data';
function emberify(obj) {
if(obj instanceof Array) {
return Ember.A(obj.map(i => emberify(i)));
} else if (obj instanceof Object) {
return Ember.Object.create(Object.keys(obj)
.reduce((hash, key) => {
hash[key] = emberify(obj[key]);
}, {}));
}
}
export default DS.Transform.extend({
deserialize: function(value) {
return emberify(obj);
}
}