-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API changes #131
API changes #131
Conversation
In regards to validateResource: ResourceValidation | ResourceValidation[]; I think the example doesn't really make sense to me. I see these three rules as separate concerns and hence they should be separate policies. I do like the "A different way to do stronger-typed resources" section. I like that it can also be used for the I think we may also need to support casting to a new interface. IE for all resources that have tags, the tags should be in this format. |
OK. I'll remove the array and update the examples to use separate policies.
Yeah, I think so -- they aren't mutually exclusive.
Hmm, yeah, we do have the following example, which kind of does this already manually without any additional built-in helpers: https://github.com/pulumi/examples/blob/567ecaf3972a48e6d5bac090c1d845d9aa1f5fbb/policy-packs/aws-advanced/compute.ts#L233-L267 |
Regarding {
name: "required-name-tag",
description: "A 'Name' tag is required.",
enforcementLevel: "mandatory",
rules: [
typedRule(aws.ec2.Instance.isInstance, it => {
requireNameTag(it.tags);
}),
typedRule(aws.ec2.Vpc.isInstance, it => {
requireNameTag(it.tags);
}),
]
},
While we're doing API design, do we also need to consider #78 ? As an example, how would I write a rule "instance must contain a 'Name' tag that ends with All in all, I'm good with the changes. |
ALSO can we come up with an example unit test? I think if @clstokes likes the multiple rules approach we should listen to him since he is closest to our user base.. I just want to make sure theres still an easy way to test this! |
It'd look like: {
name: "required-name-tag",
description: "A 'Name' tag is required.",
enforcementLevel: "mandatory",
validateResource: (args, reportViolation) => {
const instance = asResource(aws.ec2.Instance.isInstance, args);
if (instance) {
requireNameTag(instance.tags, reportViolation);
}
const vpc = asResource(aws.ec2.Vpc.isInstance, args);
if (vpc) {
requireNameTag(vpc.tags, reportViolation);
}
},
}, Or shorter by tweaking {
name: "required-name-tag",
description: "A 'Name' tag is required.",
enforcementLevel: "mandatory",
validateResource: (args, reportViolation) => {
requireNameTag(asResource(aws.ec2.Instance.isInstance, args), reportViolation);
requireNameTag(asResource(aws.ec2.Vpc.isInstance, args), reportViolation);
},
},
const requireNameTag = function (resource: any | undefined, reportViolation: ReportViolation) {
if (resource && (!resource.tags || resource.tags["Name"] === undefined)) {
reportViolation("A 'Name' tag is required.");
}
}; |
This has been taken into consideration, but will be exposed later. We can add resource options, project name, and stack name to the args. |
I'll post a couple approaches here in a little bit. The approach Joe took in pulumi/pulumi-policy-aws#2 of separating out the checks to separate exportable functions allows easily testing resources in a strongly typed way. Testing a |
This change implements the changes based on feedback after writing more rules.
We discussed {
name: "required-name-tag",
description: "A 'Name' tag is required.",
enforcementLevel: "mandatory",
validateResource: [
validateTypedResource(aws.ec2.Instance.isInstance, (it, args, reportViolation) => {
requireNameTag(it.tags, reportViolation);
}),
validateTypedResource(aws.ec2.Vpc.isInstance, (it, args, reportViolation) => {
requireNameTag(it.tags, reportViolation);
}),
],
}, Most policies will still have a single validation function, hence |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM in terms of the API itself.. do have some questions.
@@ -90,7 +96,7 @@ async function getPluginInfoRpc(call: any, callback: any): Promise<void> { | |||
} | |||
|
|||
// analyze is the RPC call that will analyze an individual resource, one at a time (i.e., check). | |||
function makeAnalyzeRpcFun(policyPackName: string, policyPackVersion: string, policies: Policy[]) { | |||
function makeAnalyzeRpcFun(policyPackName: string, policyPackVersion: string, policies: Policies) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we test if this is working as expected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've manually tested it, but I will add some actual integration tests.
Need to also check to see if `validateResource` is an array.
Verifies basic functionality. There are many more tests we should add subsequently.
Awesome thanks for taking the time to do this :) |
Apologies for the long description. This PR implements the latest API proposal, addressing some feedback since we discussed earlier this week. Please read it over and take a look at the changes in this PR and the associated PR that updates the examples pulumi/examples#441
Some changes since we discussed earlier this week:
This demonstrates a
validateTypedResource
helper for stronger typed resource checking, similar to the previoustypedRule
helper.Here's an example:
I keep waffling on changing
EnforcementLevel
,"advisory"
, and"mandatory"
toSeverity
,"warning"
, and"error"
. I don't feel strongly about it, but was initially leaning towards the less verboseSeverity
. However, Cameron pointed out we might want to add a"softMandatory"
or"requiresApproval"
value in the future, which doesn't work as well withSeverity
, so I've left itEnforcementLevel
for now. Still open to changing.Originally, I specified the
Policy
as:Which would allow setting either
validateResource
orvalidateStack
on a policy. However, Cameron's feedback was that we should not allow both.To address, I've separated these out as follows so that the compiler will enforce defining either a
validateResource
orvalidatStack
:If the additional types add too much cognitive load, we could consider going back to the simpler design with two optional properties on the main
Policy
interface. We could also consider making it a runtime check to enforce only setting one of the two properties (if we felt strongly about enforcing this). Or, we could allow both to be set, but generally recommend setting one or the other.You'll probably notice that I changed:
to:
I know we discussed how it didn't make a lot of sense to have
rules
which accepted a singlerule
(despite using this pattern elsewhere like in AWSX), and how the assumption is that most polices will have a single rule. When updating the examples, I found it was just easier to be able to provide multiple validation functions to be called for certain policies that are checking similar things across multiple resource types (e.g. EC2Instance
,LaunchConfiguration
, orLaunchTemplate
are using only approved AMIs).This is largely due to the way the
validateTypedResource
helper works to provide stronger typed resource objects to check since it only allows converting a single validation function into a strongly-typed resource. However, instead of making the property name plural (like with the previousrules
), I've left it singular as the majority of policies will only have a singlevalidateResource
validation function -- but if it's simpler to implement a policy using multiple validation functions, the option is available.Though, we could go about strongly typing the resource in a different way which could obviate the need for multiple validation functions for such policies. More below.
The implementation of
ResourceValidationPolicy
has been hooked-up, butStackValidationPolicy
has not yet. @chrsmith, want me to do it, now that your change inpulumi/pulumi
has been merged?Here's an example of a policy that is looking for potentially multiple violations, but something where you don't necessarily have to exit early when the first violation is found:
A different way to do stronger-typed resources
While the
validateTypedResource
approach to providing a strongly typed resource to program against works, it has two problems:For policies that are looking for similar things over multiple resource types, it necessitates multiple validation functions (one per resource). It'd be nice if we could keep it a single validation function, and do the stronger typed filtering inside that.
The approach won't extend to the
validateStack
check, where you'll likely also want stronger-typed resources when looking at various resources in the stack.One way to solve this would be to provide a helper like:
Basically, if we can convert the resource, we will return it as the stronger typed
q.ResolvedResource<TResource>
, otherwiseundefined
.Using it in a
validateResource
function would look like:And you could have multiple calls to
asResource
inside the single validation function, to cast to as many resource types as you'd like. Though, it's a bit more verbose and cumbersome than thevalidateTypedResource
helper.But the same
asResource
helper function could be used insidevalidateStack
to get stronger typing for the resources there.What do folks think?
Part of #87