Skip to content

Commit

Permalink
modified rule to check proxy resources, with adding more top level pr…
Browse files Browse the repository at this point in the history
…operties to the check tracked resouces (#769)
  • Loading branch information
tejaswiMinnu authored Feb 21, 2025
1 parent 6b44e59 commit 90c5153
Show file tree
Hide file tree
Showing 4 changed files with 411 additions and 25 deletions.
73 changes: 50 additions & 23 deletions packages/rulesets/src/native/functions/arm-resource-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,36 +66,63 @@ export function* trackedResourcesHavePatch(openapiSection: any, options: {}, ctx

export function* armResourcePropertiesBag(openapiSection: any, options: {}, ctx: RuleContext) {
const armHelper = new ArmHelper(ctx?.document, ctx?.specPath, ctx?.inventory!)
const allResources = armHelper.getTrackedResources()
const propertiesBag = ["name", "id", "type", "location", "tags"]
// List of top-level properties to track
const propertiesBagTracked = [
"name",
"type",
"id",
"location",
"tags",
"plan",
"sku",
"etag",
"managedby",
"identity",
"kind",
"zones",
"systemdata",
"extendedlocation",
]
// Get tracked resources from ARM helper
const trackedResources = armHelper.getTrackedResources()
// Process tracked resources with the tracked properties bag
yield* processResources(armHelper, trackedResources, propertiesBagTracked)

function checkPropertiesBag(model: any, resourceName: string, propertiesPath: string[]) {
let messages: any[] = []
const properties = armHelper.getProperty(model!, "properties")
if (properties) {
propertiesPath.push("properties")
for (const p of propertiesBag) {
if (armHelper.getProperty(properties, p)) {
messages.push(
`Top level property names should not be repeated inside the properties bag for ARM resource '${resourceName}'. Properties [${propertiesPath
.concat(p)
.join(".")}] conflict with ARM top level properties. Please rename these.`,
)
}
}
// List of proxy properties to track
const propertiesBagProxy = ["name", "id", "type", "etag", "systemdata"]
// Get proxy resources from ARM helper
const proxyResources = armHelper.getProxyResources()
// Process proxy resources with the proxy properties bag
yield* processResources(armHelper, proxyResources, propertiesBagProxy)
}

const subResult = checkPropertiesBag(properties, resourceName, propertiesPath)
messages = messages.concat(subResult)
function checkPropertiesBag(armHelper: ArmHelper, model: any, resourceName: string, propertiesBag: string[], propertiesPath: string[]) {
let messages: any[] = []
const properties = armHelper.getProperty(model!, "properties")
if (properties) {
propertiesPath.push("properties")
for (const p of propertiesBag) {
if (armHelper.getProperty(properties, p)) {
messages.push(
`Top level property names should not be repeated inside the properties bag for ARM resource '${resourceName}'. Properties [${propertiesPath
.concat(p)
.join(".")}] conflict with ARM top level properties. Please rename these.`,
)
}
}
return messages
const subResult = checkPropertiesBag(armHelper, properties, resourceName, propertiesBag, propertiesPath)
messages = messages.concat(subResult)
}
return messages
}

for (const re of allResources) {
const model = armHelper.getResourceByName(re.modelName)
const messages = checkPropertiesBag(model, re.modelName, [])
function* processResources(armHelper: ArmHelper, resources: any[], propertiesBag: string[]) {
for (const resource of resources) {
const model = armHelper.getResourceByName(resource.modelName)
const messages = checkPropertiesBag(armHelper, model, resource.modelName, propertiesBag, [])
for (const message of messages) {
yield {
location: ["definitions", re.modelName],
location: ["definitions", resource.modelName],
message,
}
}
Expand Down
18 changes: 16 additions & 2 deletions packages/rulesets/src/native/tests/migrated-arm-rule-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,34 @@ describe("IndividualAzureTests", () => {
assertValidationRuleCount(messages, ruleName, 2)
})

test("resource property bag", async () => {
test("resource property bag with tracked resource", async () => {
const fileNames = ["arm-resource-properties-bag.json"]
const ruleName = "ArmResourcePropertiesBag"
const messages: LintResultMessage[] = await collectTestMessagesFromValidator(fileNames, OpenApiTypes.arm, ruleName)
assertValidationRuleCount(messages, ruleName, 1)
})

test("resource property bag with reference", async () => {
test("resource property bag with reference and tracked resource", async () => {
const fileNames = ["arm-resource-properties-bag-with-reference.json"]
const ruleName = "ArmResourcePropertiesBag"
const messages: LintResultMessage[] = await collectTestMessagesFromValidator(fileNames, OpenApiTypes.arm, ruleName)
assertValidationRuleCount(messages, ruleName, 2)
})

test("resource property bag with proxy resource", async () => {
const fileNames = ["arm-resource-properties-bag-proxy-resource.json"]
const ruleName = "ArmResourcePropertiesBag"
const messages: LintResultMessage[] = await collectTestMessagesFromValidator(fileNames, OpenApiTypes.arm, ruleName)
assertValidationRuleCount(messages, ruleName, 1)
})

test("resource property bag with reference and proxy resource", async () => {
const fileNames = ["arm-resource-properties-bag-with-reference-proxy-resources.json"]
const ruleName = "ArmResourcePropertiesBag"
const messages: LintResultMessage[] = await collectTestMessagesFromValidator(fileNames, OpenApiTypes.arm, ruleName)
assertValidationRuleCount(messages, ruleName, 2)
})

test("resource property bag with multiple level reference", async () => {
const fileNames = ["arm-resource-properties-bag-with-multiple-level-reference.json"]
const ruleName = "ArmResourcePropertiesBag"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"swagger": "2.0",
"info": {
"title": "Microsoft Azure Redis Cache Management API",
"description": "Some cool documentation.",
"version": "2014-04-01-preview"
},
"host": "management.azure.com",
"schemes": [
"https"
],
"basePath": "/",
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"paths": {
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/Redis/{name}/Res": {
"get": {
"tags": [
"Redis"
],
"operationId": "Redis_get",
"description": "gets a Redis cache.",
"parameters": [
{
"name": "name",
"type": "string",
"required": true,
"description": "redis cache to get",
"in": "path"
}
],
"responses": {
"200": {
"description": "the resource",
"schema": {
"$ref": "#/definitions/TempResource"
}
}
}
}
},
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/Redis/{name}": {
"patch": {
"tags": [
"Redis"
],
"operationId": "Redis_update",
"description": "gets a Redis cache.",
"parameters": [
{
"name": "tag",
"type": "string",
"required": true,
"description": "tag to update"
}
],
"responses": {
"200": {
"description": "the resource patched",
"schema": {
"$ref": "#/definitions/TempResource"
}
}
}
}
},
"/operations": {
"get": {
"summary": "Lists all foo.",
"description": "foo",
"operationId": "Operations_List",
"parameters": [
{
"name": "limit",
"type": "string",
"description": "foo"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/OperationsListResult"
}
}
}
}
}
},
"definitions": {
"Resource": {
"description": "The Resource model definition.",
"properties": {
"id": {
"readOnly": true,
"type": "string",
"description": "Resource Id"
},
"name": {
"readOnly": true,
"type": "string",
"description": "Resource name"
},
"type": {
"readOnly": true,
"type": "string",
"description": "Resource type"
}
},
"x-ms-azure-resource": true
},
"TempResource": {
"allOf": [
{
"$ref": "#/definitions/Resource"
}
],
"description": "temporary resource",
"properties": {
"prop0": {
"type": "string"
},
"properties": {
"properties": {
"name": {
"type": "string",
"description": "some dummy name"
}
}
}
}
},
"OperationsListResult": {
"description": "List of operations",
"properties": {
"value": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of Operations"
}
}
}
},
"parameters": {
"SubscriptionIdParamterer": {
"name": "subscriptionId",
"in": "path",
"description": "Subscription ID.",
"required": true,
"type": "string"
},
"ApiVersionParameter": {
"name": "apiVersion",
"in": "path",
"description": "API ID.",
"required": true,
"type": "string"
}
}
}
Loading

0 comments on commit 90c5153

Please sign in to comment.