Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
tejaswiMinnu committed Feb 21, 2025
2 parents e74d2bf + 90c5153 commit ca47b46
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 ca47b46

Please sign in to comment.