diff --git a/docs/scorecards/concepts-and-structure.md b/docs/scorecards/concepts-and-structure.md index 72ecb4338b..41e7e56efc 100644 --- a/docs/scorecards/concepts-and-structure.md +++ b/docs/scorecards/concepts-and-structure.md @@ -11,22 +11,82 @@ import TabItem from "@theme/TabItem" # Concepts and structure -## Scorecard structure table +In your [Builder](https://app.getport.io/settings/data-model) page scorecards are represented by three blueprints: +- [`Scorecard`](#scorecard-structure) - Represents a collection of rules and levels for evaluating entities. +- [`Rule`](#rule-structure) - Defines specific criteria for evaluation. +- [`Rule Result`](#rule-result-structure) - Stores the evaluation results for each entity. + +## `Scorecard` structure A single scorecard defines a category to group different checks, validations and evaluations. -Below is the structure of a single scorecard: +Below is the structure of a single `scorecard` blueprint: + +| Name | Type | Description | +|------|------|-------------| +| `Identifier` | String | The unique identifier of the scorecard (Maximum 100 characters). | +| `Blueprint` | String (format: blueprints) | The target blueprint whose entities will be evaluated. | +| [`Levels`](#levels) | Array of objects | An array of levels with titles and colors (e.g., Bronze, Silver, Gold). | +| [`Filter`](#filter-elements) | Object | Optional query to filter which entities should be evaluated. | +| `Rules tested` | Number ([aggregation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property)) | Number of [rule](#rule-elements) evaluations performed. | +|` Rules passed` | Number ([aggregation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property)) | Number of successful [rule](#rule-elements) evaluations. | +| `% of rules passed` | Number ([calculation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/calculation-property)) | Calculated percentage of passed rules. | -| Field | Type | Description | -|------------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------| -| `title` | `String` | Scorecard name that will be shown in the UI | -| `identifier` | `String` | The unique identifier of the `Scorecard` (Maximum 100 characters). The identifier is used for API calls, programmatic access and distinguishing between different scorecards | -| [`filter`](#filter-elements) | `Object` | Optional set of [conditions](#conditions) to filter entities that will be evaluated by the scorecard | -| [`levels`](#levels) | `Array` | The levels that we define for the scorecard, for example `Basic`, `Bronze`, `Silver`, `Gold` | -| [`rules`](#rule-elements) | `Object` | The rules that we create for each scorecard to determine its level | +Relations: The scorecard blueprint doesn't have any relations by default. A scorecard contains and groups multiple rules that are relevant to its specific category, for example a scorecard for _service maturity_ can contain 3 rules, while the _production readiness_ scorecard can contain 2 completely different rules. -## Levels +### Constraints and restrictions + +#### Core limitations + +1. The scorecard blueprints are **protected** and their core structure **cannot be modified**: + - Default properties cannot be changed or deleted. + - Required relations cannot be modified. + - The blueprints themselves cannot be deleted. + +2. You can **extend** the blueprints with: + - New properties. + - New non-required relations. + - Additional configurations that do not affect the core functionality. + +3. Rule results are **automatically generated and managed** by Port: + - They cannot be created, deleted, or modified directly. + - You can update the custom properties you created for the rule results. + - Rule results are not searchable in the global search. + - They are updated automatically when rules are evaluated. + +#### Validation rules + +The system enforces several validation rules to maintain data integrity: + +1. Rule levels must match one of the levels defined in their parent scorecard. +2. Scorecard blueprint built-in relations cannot be renamed or modified. +3. Rule results maintain immutable core properties while allowing updates to custom properties. + +#### Delayed rule results + +When creating scorecards, adding new rules, or modifying existing rules for blueprints that contain a large number of entities, it may take some time for the `rule results` to appear in your catalog. + +This delay occurs because Port needs to create or update rule result blueprint instances for each entity and rule combination. The more entities you have in the blueprint, the more rule results need to be created or updated, which increases the processing time. + +#### Rule result entity limits + +Port supports up to **5 million** rule result entities. + +To monitor how many rule result entities you have, you can: + +1. Use the following [API path](/api-reference/get-a-blueprints-entity-count): Query the `_rule_result` blueprint identifier. +2. Create a [number chart](/customize-pages-dashboards-and-plugins/dashboards/#number-chart): + - Type: `count entities`. + - Function: `count`. + - Blueprint: `_rule_result`. + +If you reach this limit, you can: +- Contact [Port support](https://support.port.io) for assistance. +- Review your scorecards to reduce the number of rules. +- Reduce the number of entities in the blueprints that your scorecards are defined for. + +### Levels Levels are the different stages that an entity can be in, according to the rules that it passes. By default, the levels are: `Basic`, `Bronze`, `Silver`, `Gold`. @@ -49,6 +109,7 @@ If the entity didn't pass any rule, it will be at the `Basic` level, and thus ca + ```json showLineNumbers { "identifier": "Ownership", @@ -96,7 +157,8 @@ If the entity didn't pass any rule, it will be at the `Basic` level, and thus ca -```json + +```json showLineNumbers { "identifier": "monitoringMaturity", "title": "Monitoring Maturity", @@ -123,7 +185,8 @@ If the entity didn't pass any rule, it will be at the `Basic` level, and thus ca -```json + +```json showLineNumbers { "identifier": "ProductionReadiness", "title": "Production Readiness", @@ -155,21 +218,43 @@ If the entity didn't pass any rule, it will be at the `Basic` level, and thus ca -## Rule elements +**Total level calculation** + +A Scorecard is built from several rules, and each one of them has a `level` property. Each scorecard has a set of levels (as shown in the examples above). + +An entity **always** starts at the `Basic` level of the scorecard, and it can progress to higher levels by passing the rules of each level. + +Once an entity passes all the rules for a certain level, its level changes accordingly, for example: + +1. An entity starts at level `Basic`. +2. It has two rules with level `Bronze`. +3. Once the entity passes those two rules, its level would be `Bronze`. +4. It has four rules with level `Silver`. +5. Once the entity passes those four rules (and the rules from `Bronze` level), its level would be `Silver`. + +:::note multiple rules scenario +In the example listed above, let's assume the entity passes just one of the two `Bronze` rules, but it passes all of +the `Silver` rules. The `level` of the scorecard will still be `Basic`, because not all `Bronze` rules have been +satisfied. +::: + +### Rule elements Rules enable you to generate checks inside a scorecard only for entities and properties. -A scorecard rule is a single evaluation consisting of multiple checks, each rule has a level which directly translates to how important it is for the check to pass (the more basic the check, the lower its level): +A scorecard rule is a single evaluation consisting of multiple checks, each rule has a level which directly translates to how important it is for the check to pass (the more basic the check, the lower its level). -| Field | Type | Description | -|---------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `title` | `String` | `Rule` name that will be shown in the UI | -| `description` | `String` | Description that will be shown in the UI when the rule is expanded. Value that contains markdown is also supported and will be displayed in a markdown format | -| `identifier` | `String` | The unique identifier of the `Rule` (Maximum 100 characters) | -| `level` | `String` | One of the levels defined in the scorecard [levels key](#levels) | -| `query` | `Object` | The query is built from a [`combinator`](#combinator) (or / and) and an array of [`conditions`](#conditions) | +#### Conditions -### Combinator +Conditions are small boolean checks that help when determining the final status of a `query` according to the specified [`combinator`](#combinator): + +| Field | Description | +|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `operator` | Search operator to use when evaluating this rule, for example `=`, `!=`, `contains`, `doesNotContains`, `isEmpty`, `isNotEmpty` (see all [available operators](#available-operators) below). | +| `property` | Property to filter by according to its value. It can be a [meta-property](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/meta-properties.md) such as `$identifier`, or any other standard entity property such as `slack_channel` including [mirror properties](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/mirror-property) and [calculation properties](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/calculation-property/calculation-property.md). | +| `value` | Value to compare to (not required in `isEmpty` and `isNotEmpty` operators). | + +##### Combinator @@ -224,79 +309,67 @@ A scorecard rule is a single evaluation consisting of multiple checks, each rule -### Conditions - -Conditions are small boolean checks that help when determining the final status of a `query` according to the specified [`combinator`](#combinator): - -| Field | Description | -|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `operator` | Search operator to use when evaluating this rule, for example `=`, `!=`, `contains`, `doesNotContains`, `isEmpty`, `isNotEmpty` (see all available operators below) | -| `property` | Property to filter by according to its value. It can be a [meta-property](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/meta-properties.md) such as `$identifier`, or any other standard entity property such as `slack_channel` including [Mirror Properties](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/mirror-property) and [Calculation Properties](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/calculation-property/calculation-property.md) | -| `value` | Value to compare to (not required in isEmpty and isNotEmpty operators) | - -#### Available operators - -| Operator | Supported Types | Description | -|---------------------|--------------------------------------------------|-----------------------------------------------------------------------| -| `=` | `String`, `Number`, `Boolean` | checks if the rule value is equal to the entity value | -| `!=` | `String`, `Number`, `Boolean` | checks if the rule value is not equal to the entity value | -| `<=` | `Number` | checks if the rule value is less than or equal to the entity value | -| `>=` | `Number` | checks if the rule value is greater than or equal to the entity value | -| `<` | `Number` | checks if the rule value is less than the entity value | -| `>` | `Number` | checks if the rule value is greater than the entity value | -| `contains` | `String`, `Number` | checks if the rule value is contained within the entity value | -| `containsAny` | `Array` | checks if any of the specified strings exist in the target array | -| `doesNotContains` | `String`, `Number` | checks if the rule value is not contained within the entity value | -| `endsWith` | `String`, `Number` | checks if the rule value ends with the entity value | -| `doesNotEndsWith` | `String`, `Number` | checks if the rule value does not end with the entity value | -| `beginsWith` | `String`, `Number` | checks if the rule value begins with the entity value | -| `doesNotBeginsWith` | `String`, `Number` | checks if the rule value does not begin with the entity value | -| `isEmpty` | `String`, `Number`, `Boolean`, `Array`, `Object` | checks if the rule value is an empty string, array, or object | -| `isNotEmpty` | `String`, `Number`, `Boolean`, `Array`, `Object` | checks if the rule value is not an empty string, array, or object | - -## Scorecard total level calculation - -A Scorecard is built from several rules, and each one of them has a `level` property. - -Each scorecard has a set of levels, for example - -```json -{ - "levels": [ - { - "color": "paleBlue", - "title": "Basic" - }, - { - "color": "bronze", - "title": "Bronze" - }, - { - "color": "silver", - "title": "Silver" - }, - { - "color": "gold", - "title": "Gold" - } - ] -} -``` - -An entity **always** starts at the **`Basic`** level of the scorecard, and it can progress to higher levels by passing the rules of each level. - -Once an entity passes all the rules for a certain level, its level changes accordingly, for example: - -1. An entity starts at level `Basic`. -2. It has two rules with level `Bronze`. -3. Once the entity passes those two rules, its level would be `Bronze`. -4. It has four rules with level `Silver`. -5. Once the entity passes those four rules (and the rules from `Bronze` level), its level would be `Silver`. - -:::note multiple rules scenario -In the example listed above, let's assume the entity passes just one of the two `Bronze` rules, but it passes all of -the `Silver` rules. The `level` of the scorecard will still be `Basic`, because not all `Bronze` rules have been -satisfied. +##### Available operators + +| Operator | Supported Types | Description | +|---------------------|--------------------------------------------------|------------------------------------------------------------------------| +| `=` | `String`, `Number`, `Boolean` | checks if the rule value is equal to the entity value. | +| `!=` | `String`, `Number`, `Boolean` | checks if the rule value is not equal to the entity value. | +| `<=` | `Number` | checks if the rule value is less than or equal to the entity value. | +| `>=` | `Number` | checks if the rule value is greater than or equal to the entity value. | +| `<` | `Number` | checks if the rule value is less than the entity value. | +| `>` | `Number` | checks if the rule value is greater than the entity value. | +| `contains` | `String`, `Number` | checks if the rule value is contained within the entity value. | +| `containsAny` | `Array` | checks if any of the specified strings exist in the target array. | +| `doesNotContains` | `String`, `Number` | checks if the rule value is not contained within the entity value. | +| `endsWith` | `String`, `Number` | checks if the rule value ends with the entity value. | +| `doesNotEndsWith` | `String`, `Number` | checks if the rule value does not end with the entity value. | +| `beginsWith` | `String`, `Number` | checks if the rule value begins with the entity value. | +| `doesNotBeginsWith` | `String`, `Number` | checks if the rule value does not begin with the entity value. | +| `isEmpty` | `String`, `Number`, `Boolean`, `Array`, `Object` | checks if the rule value is an empty string, array, or object. | +| `isNotEmpty` | `String`, `Number`, `Boolean`, `Array`, `Object` | checks if the rule value is not an empty string, array, or object. | + +## `Scorecard Rule` structure + +The `Rule` blueprint contains the following properties: +| Name | Type | Description | +|------|------|-------------| +| `Identifier` | String | The unique identifier of the rule (Maximum 100 characters). | +| `Level` | String (enum) | The required level for this rule (must be one of the scorecard's defined levels). | +| `Query` | Object | The evaluation criteria for entities. | +| `Rule description` | String | Optional explanation of the rule's logic. | +| `Entities tested` | Number ([aggregation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property)) | Number of entities evaluated by this rule. | +| `Entities passed` | Number ([aggregation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property)) | Number of entities that passed this rule. | +| `% of entities passed` | Number ([calculation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/calculation-property)) | Calculated percentage of passed entities. | + +Relations: +| Name | Target Blueprint | Required | Many | Description | +|:----:|:----------------:|:---------:|:-----:|:-----------:| +| Scorecard | Scorecard | true | false | The scorecard this rule belongs to | + +## `Scorecard Rule Result` structure + +The `Rule result` blueprint contains the following properties: + +| Name | Type | Description | +|------|------|-------------| +| `Result` | String (enum) | Whether the entity passed the rule ("Passed" or "Not passed"). | +| `Entity` | String | The identifier of the evaluated entity. | +| `Entity link` | String (url) | Calculated URL to the evaluated entity. | +| `Result last change` | Date-Time (mirror) | Last time the rule result changed. | +| `Scorecard` | String (mirror) | Mirror property showing the parent scorecard title. | +| `Blueprint` | String (mirror) | Mirror property showing the target blueprint. | +| `Level` | String (mirror) | Mirror property from the related rule. | + +Relations: +| Name | Target Blueprint | Required | Many | Description | +|------|-----------------|----------|-------|-------------| +| Rule | Rule | true | false | The rule that generated this result. | +| [Blueprint Identifier] | [Dynamic] | false | false | Automatically created relation to the target blueprint when a new scorecard is created. | +| Owning Teams | Teams | false | true | The relation to the Team blueprint is created by default. | + +:::info Dynamic Relations +When a new scorecard is created, Port automatically creates a relation in the Rule Result blueprint to the scorecard's target blueprint. For example, if you create a scorecard for the "service" blueprint, a new relation named "service" will be added to the Rule Result blueprint. ::: ## Filter elements @@ -309,41 +382,88 @@ A scorecard filter is used to make sure only relevant entities are evaluated, on | Field | Description | |-----------------------------|-----------------------------------------------------------| -| [`combinator`](#combinator) | Defines the logical operation to apply to the query rules | -| [`conditions`](#conditions) | An array of boolean conditions to filter entities with | +| [`combinator`](#combinator) | Defines the logical operation to apply to the query rules.| +| [`conditions`](#conditions) | An array of boolean conditions to filter entities with. | ## Scorecard UI indications -After configuring scorecards for the blueprint, each entity created from it will have a `Scorecards` tab in -its [entity page](/customize-pages-dashboards-and-plugins/page/entity-page), detailing the different checks and their results: +Scorecards are available in two contexts in Port's software catalog: + +1. **Entity's scorecards** - You can view an entity's scorecard evaluation at the `scorecards` tab on the entity's specific page, which shows how the entity performs against the scorecard rules. +2. **Scorecards dashboards** - Each **scorecard** has its own entity page with a default dashboard and view that provides a comprehensive overview of the scorecard's performance across all entities. -![Developer Portal Scorecards Tab](../../static/img/software-catalog/scorecard/tutorial/ScorecardsTab.png) +### Entity's scorecards + +Each entity with a configured scorecard will have a `scorecards` tab in its [entity page](/customize-pages-dashboards-and-plugins/page/entity-page), detailing the different checks and their results: + + +



Additionally, the [catalog page](/customize-pages-dashboards-and-plugins/page/catalog-page) of each blueprint will automatically have a column for each scorecard rule. -For example, this `service` blueprint has 4 rules configured, and we can see a column for each of them in the catalog: +For example, this `Microservice` blueprint has five rules configured, and we can see a column for each of them in the catalog: -![catalogPageScorecardColumns](../../static/img/software-catalog/scorecard/catalogPageScorecardColumns.png) + -### Customizing views +#### Customizing views You can use table operations (sort, edit, group-by, etc.) to create various helpful views of your scorecards. -For example, here are the scores of all `Services` in an organization grouped by team: +For example, here are the scores of all `Microservice` in an organization grouped by team: -![catalogViewScorecardsByTeam](../../static/img/software-catalog/scorecard/catalogViewScorecardsByTeam.png) + Note that every column (scorecard metric) in the table has an aggregation in the bottom, hover over it to see the compliance of this metric across all entities in the table. -### Rule result summaries +#### Rule result summaries Scorecard rules are automatically added as columns in the relevant catalog page, and each such column is summarized on the bottom. -For example, these services have some rules defined in their scorecards, and we can see that: +For example, these microservices have some rules defined in their scorecards, and we can see that: + +- 100% of `Ecosystem team's` microservices have an on-call defined, but only 67% of them have domain configured. +- The bottom of the table contains an aggregation of the results of each rule for all microservices (across all teams). Six + out of eight microservices in total have a domain configured. + + + +### Scorecards dashboards + +By default, admins have a **Scorecard catalog** folder in their software catalog that contains three dashboards: + +- [**Scorecards**](https://app.getport.io/_scorecards) - Displays your scorecards across all blueprints. +- [**Scorecards rules**](https://app.getport.io/_rules) - Displays the different scorecard rules across all scorecards. +- [**Scorecards rule results**](https://app.getport.io/_rule_results) - Displays the rule results for each scorecard rules. + +#### Scorecard specific entity page + +Each scorecard, rule, and rule result has its own [entity page](/customize-pages-dashboards-and-plugins/page/entity-page) with a default dashboard. For scorecards, the dashboard provides a comprehensive overview of the scorecard's performance across all entities. + +The scorecard entity page dashboard includes default widgets such as: + +- **% of rules passed** - A numerical display showing the overall percentage of rules that have passed for the scorecard. +- **Rules passed** - A pie chart visualizing the breakdown of passed versus not passed rules. +- **% of passed rules over time** - A line chart tracking the historical trend of the percentage of rules passed over time. +- **Rule results summary** - A detailed table breaking down individual rule results, including level, rule name, entity, and result status. + +You can customize the dashboard by adding additional widgets or modifying existing ones to display other aggregations, calculations, and visualizations based on your requirements. + +## Scorecard permission management + +Admins can control who can view and manage scorecards. + +**Permission examples:** + +Here are some common permission configurations: + +- Security scorecards can be edited only by the security team. +- The Production Readiness scorecard can be edited by directors. +- If the scorecard category is `production`, only SREs can edit it. + +**Permission behavior:** + +- If a user has the `register` permission to the `scorecard` blueprint, they can create scorecards on any other blueprint. The rules defined in the scorecard will be created as a result, even if the user is not a `scorecard rule` blueprint moderator. +- A user with a `moderator` role on a blueprint can create scorecards **for that specific blueprint**. They can add them using the `+ New scorecard` button in the blueprint’s scorecards tab in the [Builder](https://app.getport.io/settings/data-model) page. -- 100% of `Team Batman's` services have an on-call defined, but only 67% of them have a PR cycle time shorter than 1500 - minutes. -- The bottom of the table contains an aggregation of the results of each rule for all services (across all teams). 11 - out of 18 services in total have a build success rate that is higher than 70%. -![catalogRuleSummaries](../../static/img/software-catalog/scorecard/catalogRuleSummaries.png) +For more information on configuring permissions, refer to the [documentation](/build-your-software-catalog/set-catalog-rbac/examples). ## Next steps diff --git a/docs/scorecards/examples.md b/docs/scorecards/examples.md deleted file mode 100644 index 80a9808b17..0000000000 --- a/docs/scorecards/examples.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -sidebar_position: 4 ---- - -# Examples - -### Ownership scorecard - -The following example demonstrates an ownership scorecard. - -It has one filter defined: - -- Only evaluate entities that are related to production (indicated by checking that the `is_production` property is set to `true`). - -It has two rules: - -- Check that a defined on-call exists and that the number of `open_incidents` is lower than 5; -- Check if a team exists. - -```json showLineNumbers -[ - { - "title": "Ownership", - "identifier": "ownership", - "filter": { - "combinator": "and", - "conditions": [ - { - "property": "is_production", - "operator": "=", - "value": true - } - ] - }, - "rules": [ - { - "title": "Has on call?", - "identifier": "has_on_call", - "level": "Gold", - "query": { - "combinator": "and", - "conditions": [ - { - "operator": "isNotEmpty", - "property": "on_call" - }, - { - "operator": "<", - "property": "open_incidents", - "value": 5 - } - ] - } - }, - { - "title": "Has a team?", - "identifier": "has_team", - "level": "Silver", - "query": { - "combinator": "and", - "conditions": [ - { - "operator": "isNotEmpty", - "property": "$team" - } - ] - } - } - ] - } -] -``` -___ - -### Ensure relation existence - -Say we have a `service` blueprint that has a relation to another blueprint named `domain`. -We can define a scorecard that checks that all of our services have a related domain. Services with empty `domain` relations will fail this check: - -```json showLineNumbers -{ - "title": "Domain definition", - "identifier": "domain_definition", - "rules": [ - { - "identifier": "hasDomain", - "title": "Has domain", - "level": "Bronze", - "query": { - "combinator": "and", - "conditions": [ - { - "operator": "isNotEmpty", - "relation": "domain" - } - ] - } - } - ] -} -``` - -___ - -### DORA metrics based on number of deployments - -To assess the deployment frequency of a `service`, simply checking the `deployment` relation is not enough — we need to know the exact number of deployments. To achieve this, we can: - -- Add an [aggregation property](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property.md) to the `service` blueprint that counts the number of related `deployment` entities. -- Add a scorecard with a rule based on the new aggregation property: - -```json showLineNumbers -{ - "title": "DORA Metrics", - "identifier": "dora_metrics", - "rules": [ - { - "identifier": "deployFreqBronze", - "title": "Deployment frequency > 2", - "level": "Bronze", - "query": { - "combinator": "and", - "conditions": [ - { - "operator": ">", - "property": "deployment_frequency", - "value": 3 - } - ] - } - }, - { - "identifier": "deployFreqSilver", - "title": "Deployment frequency > 4", - "level": "Silver", - "query": { - "combinator": "and", - "conditions": [ - { - "operator": ">", - "property": "deployment_frequency", - "value": 4 - } - ] - } - } - ] -} -``` diff --git a/docs/scorecards/examples/_category_.json b/docs/scorecards/examples/_category_.json new file mode 100644 index 0000000000..493215ded5 --- /dev/null +++ b/docs/scorecards/examples/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Examples", + "position": 4 +} diff --git a/docs/scorecards/examples/automation-use-cases.md b/docs/scorecards/examples/automation-use-cases.md new file mode 100644 index 0000000000..c3bfb384b8 --- /dev/null +++ b/docs/scorecards/examples/automation-use-cases.md @@ -0,0 +1,215 @@ +--- +sidebar_position: 2 +--- + +# Automation use-cases + +This page provides examples of automations that trigger when scorecard rule results are updated. These examples demonstrate how to notify teams via Slack or Microsoft Teams when rule results change, and how to automatically create GitHub issues when rule results degrade from `Passed` to `Not passed`. + +## Notify on scorecard rule result updates + +### Automation definition + +By using the `ENTITY_UPDATED` trigger type, we can run custom logic whenever an entity of a specific type is updated. + +The following configuration will cause a message to be sent whenever a scorecard rule result is updated: + +
+Automation configuration (click to expand) + +**Remember to change `github-org-name` and `github-repo-name` to your GitHub organization name and repository in the highlighted lines.** + +```json showLineNumbers +{ +"identifier": "ruleResultUpdated", +"title": "Rule result updated", +"trigger": { + "type": "automation", + "event": { + "type": "ENTITY_UPDATED", + "blueprintIdentifier": "_rule_result" + } +}, +"invocationMethod": { + "type": "GITHUB", + # highlight-start + "org": "github-org-name", + "repo": "github-repo-name", + # highlight-end + "workflow": "notify-rule-result-updated.yaml", + "workflowInputs": { + "rule_result_name": "{{ .event.context.entityIdentifier }}", + "entity_link": "{{ .event.diff.after.properties.entity_link }}" + }, + "reportWorkflowStatus": true +}, +"publish": true +} +``` +
+ +* `invocationMethod.workflowInputs` is the payload to be passed to the GitHub workflow upon every execution. In this example, we pass the rule result's identifier and the link to the evaluated entity. + +* `invocationMethod.reportWorkflowStatus` is set to `true` to automatically update the action run in Port with the status of the GitHub workflow. + +### Backend - GitHub workflow + +The `notify-rule-result-updated.yaml` workflow will contain the logic to send a Slack/Teams message. + +

Prerequisite - set up webhooks

+ +The workflow requires a Slack webhook URL and/or a Microsoft Teams webhook URL to send the message. + +Slack: +1. To set up a Slack webhook, follow the instructions [here](https://api.slack.com/messaging/webhooks). +2. Once you have the webhook URL, add it as a secret in your GitHub repository named `SLACK_WEBHOOK_URL`. + +Microsoft Teams: +1. To set up a Microsoft Teams webhook, follow the instructions [here](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook). +2. Once you have the webhook URL, add it as a secret in your GitHub repository named `TEAMS_WEBHOOK_URL`. + +
+GitHub workflow (click to expand) + +This workflow includes steps to send a message via **Slack** and **Microsoft Teams**. +**Use only the step(s) that apply to your use case.** + +```yaml showLineNumbers title="notify-rule-result-updated.yaml" +name: Notify when rule result is updated + +on: + workflow_dispatch: + inputs: + # Note that the inputs are the same as the payload (workflowInputs) defined in the automation + rule_result_name: + description: "The rule result's name" + required: true + type: string + entity_link: + description: "A link to the evaluated entity" + required: true + type: string + +jobs: + send_message: + runs-on: ubuntu-latest + steps: + - name: Send message to Slack + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + run: | + curl -X POST -H 'Content-type: application/json' --data '{"text":"The rule result ${{ inputs.rule_result_name }} has been updated. See evaluated entity: https://app.port.io${{ inputs.entity_link }}"}' $SLACK_WEBHOOK_URL + + - name: Send message to Microsoft Teams + env: + TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_WEBHOOK_URL }} + run: | + curl -H 'Content-Type: application/json' -d '{"text":"The rule result ${{ inputs.rule_result_name }} has been updated. See evaluated entity: https://app.port.io${{ inputs.entity_link }}"}' $TEAMS_WEBHOOK_URL +``` +
+ +

+___ +

+ +## Create a GitHub issue whenever a scorecard rule result is degraded + +### Automation definition + +By using the `ENTITY_UPDATED` trigger type, we can run custom logic whenever an entity of a specific type is updated. + +The following configuration will create a GitHub issue whenever a scorecard rule result's `Result` property changes from `Passed` to `Not passed`: + +
+Automation configuration (click to expand) + +**Remember to change `github-org-name` and `github-repo-name` to your GitHub organization name and repository in the highlighted lines.** + +```json showLineNumbers +{ + "identifier": "ruleResultDegraded", + "title": "Rule result degraded", + "trigger": { + "type": "automation", + "event": { + "type": "ENTITY_UPDATED", + "blueprintIdentifier": "_rule_result" + }, + "condition": { + "type": "JQ", + "expressions": [ + ".diff.before.properties.result == \"Passed\"", + ".diff.after.properties.result == \"Not passed\"" + ], + "combinator": "and" + } + }, + "invocationMethod": { + "type": "GITHUB", + # highlight-start + "org": "github-org-name", + "repo": "github-repo-name", + # highlight-end + "workflow": "create-issue-on-rule-degradation.yaml", + "workflowInputs": { + "rule_result_name": "{{ .event.context.entityIdentifier }}", + "entity_link": "{{ .event.diff.after.properties.entity_link }}" + }, + "reportWorkflowStatus": true + }, + "publish": true +} +``` +
+ +* `trigger.condition` checks the rule result's `Result` property before and after the update. The automation will only run for rule results that have been degraded. + +* `invocationMethod.workflowInputs` is the payload to be passed to the GitHub workflow upon every execution. In this example, we pass the rule result's identifier and the link to the evaluated entity. + +* `invocationMethod.reportWorkflowStatus` is set to `true` to automatically update the action run in Port with the status of the GitHub workflow. + +### Backend - GitHub workflow + +The `create-issue-on-rule-degradation.yaml` workflow will contain the logic to create a GitHub issue. + +
+GitHub workflow (click to expand) + +```yaml showLineNumbers title="create-issue-on-rule-degradation.yaml" +name: Create issue when rule is degraded + +on: + workflow_dispatch: + inputs: + # Note that the inputs are the same as the payload (workflowInputs) defined in the automation + rule_result_name: + description: 'The rule result name' + required: true + type: string + entity_link: + description: 'A link to the evaluated entity' + required: true + type: string + +# Grant write access to issues so the workflow can create them +permissions: + contents: read + issues: write + +jobs: + send_message: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: create an issue + uses: dacbd/create-issue-action@main + with: + token: ${{ github.token }} + # By default, the issue will be created in the same repository as the workflow + repo: ${{ github.context.repo.repo}} + title: '${{ inputs.rule_result_name }} - degraded rule result' + body: | + The rule result ${{ inputs.rule_result_name }} has been degraded. + See evaluated entity: https://app.port.io${{ inputs.entity_link }} +``` +
\ No newline at end of file diff --git a/docs/scorecards/examples/scorecard-use-cases.md b/docs/scorecards/examples/scorecard-use-cases.md new file mode 100644 index 0000000000..d81fe9b1a3 --- /dev/null +++ b/docs/scorecards/examples/scorecard-use-cases.md @@ -0,0 +1,849 @@ +--- +sidebar_position: 1 +--- + +# Scorecard use-cases + +This page provides examples of scorecards and related automations and self-service actions. + +The [basic examples](#basic-examples) section demonstrates common scorecard patterns. + +For more advanced use cases, see the [advanced examples](#advanced-examples) section, which shows how to extend the scorecard data model with additional properties to enable SLA tracking, due date management, and automated workflows that go beyond simple pass or fail compliance. + +## Basic examples + +In this section we are going to demonstrate scorecard examples and automations that respond to scorecard rule result changes. + +### Ownership scorecard + +The following example demonstrates an ownership scorecard. + +It has one filter defined: + +- Only evaluate entities that are related to production (indicated by checking that the `is_production` property is set to `true`). + +It has two rules: + +- Check that a defined on-call exists and that the number of `open_incidents` is lower than 5. +- Check if a team exists. + +
+Ownership scorecard definition (click to expand) + +```json showLineNumbers +{ + "identifier": "ownership", + "title": "Ownership", + "filter": { + "combinator": "and", + "conditions": [ + { + "property": "is_production", + "operator": "=", + "value": true + } + ] + }, + "rules": [ + { + "title": "Has on call?", + "identifier": "has_on_call", + "level": "Gold", + "query": { + "combinator": "and", + "conditions": [ + { + "operator": "isNotEmpty", + "property": "on_call" + }, + { + "operator": "<", + "property": "open_incidents", + "value": 5 + } + ] + } + }, + { + "title": "Has a team?", + "identifier": "has_team", + "level": "Silver", + "query": { + "combinator": "and", + "conditions": [ + { + "operator": "isNotEmpty", + "relation": "team" + } + ] + } + } + ], + "levels": [ + { + "color": "paleBlue", + "title": "Basic" + }, + { + "color": "bronze", + "title": "Bronze" + }, + { + "color": "silver", + "title": "Silver" + }, + { + "color": "gold", + "title": "Gold" + } + ] +} +``` +
+ +

+___ +

+ +### Ensure relation existence + +Say we have a `service` blueprint that has a relation to another blueprint named `domain`. +We can define a scorecard that checks that all of our services have a related domain. Services with empty `domain` relations will fail this check: + +
+Ensure relation existence scorecard definition (click to expand) + +```json showLineNumbers +{ + "identifier": "domain_definition", + "title": "Domain definition", + "rules": [ + { + "identifier": "hasDomain", + "title": "Has domain", + "level": "Bronze", + "query": { + "combinator": "and", + "conditions": [ + { + "operator": "isNotEmpty", + "relation": "domain" + } + ] + } + } + ], + "levels": [ + { + "color": "paleBlue", + "title": "Basic" + }, + { + "color": "bronze", + "title": "Bronze" + }, + { + "color": "silver", + "title": "Silver" + }, + { + "color": "gold", + "title": "Gold" + } + ] +} +``` +
+ +

+___ +

+ +### DORA metrics based on number of deployments + +To assess the deployment frequency of a `service`, simply checking the `deployment` relation is not enough — we need to know the exact number of deployments. To achieve this, we can: + +- Add an [aggregation property](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property.md) to the `service` blueprint that counts the number of related `deployment` entities. +- Add a scorecard with a rule based on the new aggregation property: + +
+DORA metrics scorecard definition (click to expand) + +```json showLineNumbers +{ + "identifier": "dora_metrics", + "title": "DORA Metrics", + "rules": [ + { + "identifier": "deployFreqBronze", + "title": "Deployment frequency > 2", + "level": "Bronze", + "query": { + "combinator": "and", + "conditions": [ + { + "operator": ">", + "property": "deployment_frequency", + "value": 3 + } + ] + } + }, + { + "identifier": "deployFreqSilver", + "title": "Deployment frequency > 4", + "level": "Silver", + "query": { + "combinator": "and", + "conditions": [ + { + "operator": ">", + "property": "deployment_frequency", + "value": 4 + } + ] + } + } + ], + "levels": [ + { + "color": "paleBlue", + "title": "Basic" + }, + { + "color": "bronze", + "title": "Bronze" + }, + { + "color": "silver", + "title": "Silver" + }, + { + "color": "gold", + "title": "Gold" + } + ] +} +``` +
+ +

+___ + +## Advanced examples + +Scorecards can track more than pass or fail compliance. By extending their data models and using [automations](/actions-and-automations/define-automations/), you can build SLA aware workflows and visual dashboards that help teams stay accountable and proactive. + +This page demonstrates real-world examples of how to do that. From extending the scorecard data model to automating SLA management and adding [self-service actions](/actions-and-automations/create-self-service-experiences/) that make scorecards truly actionable. + +### Extend the data model + +The scorecard blueprints (`Scorecard`, `Scorecard rule`, and `Scorecard rule result`) can be extended with additional properties to support more advanced use cases. + +In this example, we are going to add the following properties: + +- **Due date** - Track when a rule or rule result needs to be addressed. This property can be automatically updated by automations based on business logic. +- **SLA (Service Level Agreement)** - Define the expected time to remediate issues identified by a rule, enabling SLA tracking and compliance monitoring. +- **Hours until SLA due** - A calculation property that dynamically calculates the time remaining until the SLA due date, useful for triggering reminders and tracking approaching deadlines. + +**To create a new property:** + +1. Navigate to the [Builder](https://app.getport.io/settings/data-model) page of your portal. + +2. Expand the blueprint you want to edit, for example the scorecard rule blueprint. + +3. Click on the `+ New property` button. + +4. Choose the relevant type. + +5. Fill in the form with the desired property details. + +6. Click `Create`. + +

+**Extended scorecard rule blueprint** + +The following example shows an extended `Scorecard rule` blueprint with additional properties including `Due date` and `SLA`: + +
+Due date property definition (click to expand) + +For the `Due date` property, fill in the form with following details: + +- **Type**: Date & time. +- **Title**: Due date. + +You can also edit the blueprint's JSON form by clicking on the `...` in the top right corner of the blueprint, then choosing `Edit blueprint`. +Copy and paste the following JSON snippet under the `properties` section. + +```json showLineNumebrs + +"schema": { + "properties": { + "due_date": { + "title": "Due date", + "icon": "Flag", + "type": "string", + "format": "date-time" + } + } +} +``` +
+ +
+SLA property definition (click to expand) + +For the `SLA` property, fill in the from with following details: + +- **Type**: Number. +- **Title**: SLA. +- **Description**: Days to remidate action item. + +You can also edit the blueprint's JSON form by clicking on the `...` in the top right corner of the blueprint, then choosing `Edit blueprint`. +Copy and paste the following JSON snippet under the `properties` section. + +```json showLineNumebrs +"schema": { + "properties": { + "sla": { + "type": "number", + "title": "SLA", + "description": "Days to remediate action item ", + "icon": "Clock" + } + } +} +``` +
+ +

+**Extended scorecard rule result blueprint** + +The following example shows an extended `Scorecard rule result` blueprint with additional properties including `Due date`, `SLA`, and `Hours until SLA due`: + +
+SLA due date property definition (click to expand) + +For the `SLA due date` property, fill in the from with following details: + +- **Type**: Timer. +- **Title**: SLA due date. +- **Description**: Time to remediate based based on the SLA. + +You can also edit the blueprint's JSON form by clicking on the `...` in the top right corner of the blueprint, then choosing `Edit blueprint`. +Copy and paste the following JSON snippet under the `properties` section. + +```json showLineNumebrs +"schema": { + "properties": { + "sla_due_date": { + "type": "string", + "title": "SLA due date", + "description": "Time to remediate based based on the SLA ", + "icon": "HourGlass", + "format": "timer" + } + } +} +``` +
+ +
+Due date property definition (click to expand) + +For the `Due date` property, fill in the form with following details: + +- **Type**: Date & time. +- **Title**: Due date. + +You can also edit the blueprint's JSON form by clicking on the `...` in the top right corner of the blueprint, then choosing `Edit blueprint`. +Copy and paste the following JSON snippet under the `properties` section. + +```json showLineNumebrs +"schema": { + "properties": { + "due_date": { + "title": "Due date", + "icon": "Flag", + "type": "string", + "format": "date-time" + } + } +} +``` +
+ +
+Hours until SLA due date property definition (click to expand) + +For the `Hours until SLA due date` property, fill in the form with following details: + +- **Type**: Timer. +- **Title**: Hours until SLA due date. + +You can also edit the blueprint's JSON form by clicking on the `...` in the top right corner of the blueprint, then choosing `Edit blueprint`. +Copy and paste the following JSON snippet under the `properties` section. + +```json showLineNumebrs +"schema": { + "properties": { + "hours_until_sla_due": { + "type": "string", + "title": "Hours until SLA due date", + "format": "timer" + } + } +} +``` +
+ +
+SLA mirror property definition (click to expand) + +For the `SLA` mirror property, fill in the form with following details: + +- **Type**: Mirror. +- **Title**: Due date. +- **Relation**: Rule. +- **Mirror from**: Scorecard rule. + +You can also edit the blueprint's JSON form by clicking on the `...` in the top right corner of the blueprint, then choosing `Edit blueprint`. +Copy and paste the following JSON snippet under the `properties` section. + +```json showLineNumebrs +"schema": { + "mirrorProperties": { + "sla": { + "path": "rule.sla" + } + } +} +``` +
+ +### Automate SLA tracking + +With the data model extended, automations can enforce and monitor SLA timelines automatically. + +Let’s look at two examples: + +1. [Set action item due date](#set-action-item-due-date). +2. [Send reminder for upcoming due dates](#send-reminder-for-upcoming-due-dates). + +**Set action item due date** + +When a scorecard rule fails (changes from `Passed` to `Not passed`), this automation sets the `SLA due date` and `Hours until SLA due` properties on the rule result based on the SLA defined on the rule. This ensures that action items have a clear deadline for remediation based on the rule's SLA requirements, and enables timer-based reminders when the deadline approaches. + +The automation triggers when a rule result's `result` property changes from "Passed" to "Not passed". + +The `SLA due date` value is calculated by: +1. Taking the SLA value (in days) from the rule. +2. Converting it to seconds (multiplying by 24 * 60 * 60). +3. Adding it to the `result last change` timestamp (when the rule failed). +4. Converting the result to a date-time format. + +The `Hours until SLA due` property is set to 24 hours before the `SLA due date`, creating a timer property that expires when the reminder should be sent. This timer is used by the [reminder automation](#send-reminder-for-upcoming-due-dates) to trigger notifications when action items are approaching their SLA deadlines. + +
+Automation definition (click to expand) + +```json showLineNumbers +{ + "identifier": "set-action-item-due-date", + "title": "Set action item due-date", + "description": "When a requirement fails, set a due date to it's action item based on the SLA defined on the requirement", + "icon": "HourGlass", + "trigger": { + "type": "automation", + "event": { + "type": "ENTITY_UPDATED", + "blueprintIdentifier": "_rule_result" + }, + "condition": { + "type": "JQ", + "expressions": [ + ".diff.before.properties.result == \"Passed\"", + ".diff.after.properties.result == \"Not passed\"", + ".diff.before.properties.result_last_change != .diff.after.properties.result_last_change" + ], + "combinator": "and" + } + }, + "invocationMethod": { + "type": "UPSERT_ENTITY", + "blueprintIdentifier": "_rule_result", + "mapping": { + "identifier": "{{ .event.context.entityIdentifier }}", + "properties": { + "sla_due_date": "{{((.event.diff.before.properties.sla * 24 * 60 * 60) + ( .event.diff.after.properties.result_last_change | split(\".\")| .[0] | . + \"Z\" | fromdate)) | todate}}", + "hours_until_sla_due": "{{(((.event.diff.before.properties.sla * 24 * 60 * 60) + ( .event.diff.after.properties.result_last_change | split(\".\")| .[0] | . + \"Z\" | fromdate)) - (24 * 60 * 60)) | todate}}" + } + } + }, + "publish": true +} +``` +
+ +This automation creates a timer that counts down to the remediation deadline. The timer can be displayed in dashboards to track SLA compliance, and it can also be used by other automations, such as the reminder automation below, to notify developers when the due date is approaching. + +**Send reminder for upcoming due dates** + +Once SLA due dates are set, you can add another automation to send reminders when deadlines approach. This uses the calculation property `Hour until SLA due` to detect when an item is within 24 hours of expiration. + +
+Automation definition (click to expand) + +```json showLineNumbers +{ + "identifier": "send_reminder_for_upcoming_due_date", + "title": "Send reminder for upcoming due date", + "description": "Sends a reminder when an action item is approaching its SLA due date (within 24 hours)", + "icon": "HourGlassExpired", + "trigger": { + "type": "automation", + "event": { + "type": "TIMER_PROPERTY_EXPIRED", + "blueprintIdentifier": "_rule_result", + "propertyIdentifier": "hours_until_sla_due" + }, + "condition": { + "type": "JQ", + "expressions": [], + "combinator": "and" + } + }, + "invocationMethod": { + "type": "SLACK", + "url": "https://hooks.slack.com/services/YOUR-WEBHOOK-URL + "agent": false, + "synchronized": true, + "body": { + "text": "⚠️ *Action Item SLA Due Date Reminder*\n\nThis is a reminder that an action item's SLA due date is approaching within 24 hours.\n\n*Action Item Information:*\n• *Rule Result Identifier:* {{ .event.context.entityIdentifier }}\n• *Blueprint:* {{ .event.context.blueprintIdentifier }}\n\n*Required Action:*\nPlease review and address this action item promptly to ensure SLA compliance. The action item requires remediation to meet the defined service level agreement.\n\nYou can view the complete action item details and related information in your Port catalog at: https://app.getport.io{{ .event.diff.after.properties.entity_link }} you have any questions or need assistance, please contact your team lead or the responsible party for this action item." + }, + "method": "POST", + "headers": {} + }, + "publish": true +} +``` +
+ +### Handle SLA exceptions + +Not all action items can be resolved before their SLA expires. With the following self-service action, teams can request a due date extension directly from the catalog. + +**Request a due date extension** + +When an action item's due date is approaching and the issue cannot be resolved in time, teams can use this self-service action to request an extension from management. The action creates an exception request that goes through an approval workflow (director and VP approval). + +This action is particularly useful when: +- The due date is almost here and the action item has not been addressed yet. +- External dependencies or resource constraints prevent timely remediation. +- Additional time is needed to properly address the issue. + +For the following self-service action we will need to add another blueprint: + +1. Navigate to the [Builder](https://app.getport.io/settings/data-model) page. + +2. Click on the `+ Blueprint` button. + +3. Click on the `{...} Edit JSON` button in the top right corner of the window. + +4. Copy and paste the following JSON configuration into the editor: + +
+ Exception request blueprint (click to expand) + + ```json showLineNumbers + { + "identifier": "exception_request", + "description": "Represent all exceptions requested for open action items", + "title": "Exception request ", + "icon": "Clock", + "schema": { + "properties": { + "justification": { + "icon": "BlankPage", + "type": "string", + "title": "Justification " + }, + "director_status": { + "icon": "DefaultProperty", + "title": "Director Approval Status", + "type": "string", + "default": "Pending", + "enum": [ + "Approved", + "Not Approved", + "Pending" + ], + "enumColors": { + "Approved": "green", + "Not Approved": "red", + "Pending": "yellow" + } + }, + "vp_approved": { + "icon": "DefaultProperty", + "title": "VP Approval Status", + "type": "string", + "default": "Pending", + "enum": [ + "Approved", + "Not Approved", + "Pending" + ], + "enumColors": { + "Approved": "green", + "Not Approved": "red", + "Pending": "yellow" + } + }, + "category": { + "type": "string", + "title": "Category", + "enum": [ + "Complexity", + "No resources", + "MSFT dependencies" + ], + "enumColors": { + "Complexity": "blue", + "No resources": "lightGray", + "MSFT dependencies": "orange" + } + }, + "requested_due_date": { + "type": "string", + "title": "Requested Due date", + "icon": "Clock", + "format": "date-time" + } + }, + "required": [] + }, + "mirrorProperties": { + "current_due_date": { + "title": "Current Due Date", + "path": "requirement.due_date" + }, + "scorecard": { + "title": "Scorecard", + "path": "action_item.rule.scorecard.$title" + } + }, + "calculationProperties": { + "current_status": { + "title": "Current Status", + "icon": "DefaultProperty", + "calculation": "if .properties.director_status == \"Pending\" and .properties.vp_approved == \"Pending\" then \"Pending Director and VP\" elif .properties.director_status == \"Pending\" then \"Pending Director\" elif .properties.vp_approved == \"Pending\" then \"Pending VP\" elif .properties.director_status == \"Not Approved\" or .properties.vp_approved == \"Not Approved\" then \"Not Approved\" else \"Approved\" end", + "type": "string", + "colorized": true, + "colors": { + "Pending Director and VP": "orange", + "Pending Director": "yellow", + "Pending VP": "yellow", + "Approved": "green", + "Not Approved": "red" + } + } + }, + "aggregationProperties": {}, + "relations": { + "requirement": { + "title": "Requirement ", + "target": "_rule", + "required": false, + "many": false + }, + "approving_v_ps": { + "title": "Approving VPs", + "target": "_user", + "required": false, + "many": true + }, + "action_item": { + "title": "Rule Result", + "target": "_rule_result", + "required": false, + "many": false + }, + "approving_directors": { + "title": "Approving Directors", + "target": "_user", + "required": false, + "many": true + } + } + } + ``` +
+ +5. Click `Save`. + +To add the self-service action: + +1. Head to the [self-service](https://app.getport.io/self-serve) page. + +2. Click on the `+ New Action` button. + +3. Click on the `{...} Edit JSON` button. + +4. Copy and paste the following JSON configuration into the editor: + +
+ Self-service action definition (click to expand) + + ```json showLineNumbers + { + "identifier": "request_a_due_date_extension", + "title": "Request a due date extension", + "description": "Request an exception to extend the due date for an action item. This will require director and VP approval.", + "trigger": { + "type": "self-service", + "operation": "DAY-2", + "userInputs": { + "properties": { + "reason_for_exception": { + "icon": "DefaultProperty", + "type": "string", + "title": "Reason for Exception", + "minLength": 10, + "maxLength": 500 + }, + "exception_category": { + "icon": "DefaultProperty", + "type": "string", + "title": "Exception Category", + "description": "This will help the user to auto select the reason for exceptions", + "enum": [ + "Complexity", + "No resources", + "MSFT dependencies" + ], + "enumColors": { + "Complexity": "purple", + "No resources": "red", + "MSFT dependencies": "green" + } + }, + "date_of_resolution": { + "type": "string", + "title": "Date of Resolution", + "format": "date-time" + }, + "director_approval": { + "icon": "DefaultProperty", + "type": "array", + "title": "Director Approval", + "description": "For now we will have the requestor manually select the approver, but in the future we want Port to automatically select the next level manager for approval.", + "items": { + "type": "string", + "format": "user" + } + }, + "vp_approval": { + "icon": "DefaultProperty", + "type": "array", + "title": "VP Approval", + "items": { + "type": "string", + "format": "user" + } + } + }, + "required": [ + "reason_for_exception", + "date_of_resolution", + "director_approval", + "vp_approval" + ], + "order": [ + "exception_category", + "reason_for_exception", + "date_of_resolution", + "director_approval", + "vp_approval" + ] + }, + "blueprintIdentifier": "_rule_result" + }, + "invocationMethod": { + "type": "UPSERT_ENTITY", + "blueprintIdentifier": "exception_request", + "mapping": { + "identifier": "{{ .entity.identifier + \"_exception\"}}", + "title": "{{ .entity.title + \"_exception\"}}", + "properties": { + "justification": "{{.inputs.reason_for_exception}}", + "requested_due_date": "{{.inputs.date_of_resolution}}", + "category": "{{.inputs.exception_category}}" + }, + "relations": { + "action_item": "{{ .entity.identifier }}", + "requirement": "{{ .entity.relations.rule }}", + "approving_directors": "{{.inputs.director_approval}}", + "approving_v_ps": "{{.inputs.vp_approval}}" + } + } + }, + "requiredApproval": false, + "icon": "HourGlass" + } + ``` +
+ +5. Click `Save`. + +### Visualize and track action items + +To help teams stay accountable and proactive, you can create an action items dashboard that provides a centralized view of all failed rule results, which are the items that require remediation before SLA deadlines are missed. + +This dashboard is built on the `Scorecard rule result` blueprint and groups results by blueprint and rule, making it easy to identify and prioritize issues. + + +



+ +Who can benefit from this dashboard? + +- **Developers**: Can quickly see what issues need to be addressed for their services, prioritize work based on due dates and criticality, and track their remediation progress. +- **Team leaders**: Can monitor team-wide action items, identify patterns across services, and ensure timely remediation. They can use the dashboard to send Slack messages to developers, on-call engineers, or owning teams when action items require attention. + +**Dashboard setup** + +1. Navigate to your [Software Catalog](https://app.getport.io/catalog) page. +2. Click the **+ New** button in the sidebar on the left side of the page. +3. Select **New catalog page** from the dropdown menu. +4. In the modal that appears, configure the following settings: + - **Title**: Enter `My Action Items`. + - **Identifier**: Enter `my_action_items`. + - **Blueprint**: Select `Scorecard Rule Result` from the dropdown. +5. Set up the initial filter to show only rule results that have failed: + - Click on **filters**, then `+ Filter`. + - Select the `Result` property. + - Choose the operator `=`. + - Set the value to `Not passed`. + + Or copy and paste the following JSON code: + + ```json showLineNumbers + { + "combinator": "and", + "rules": [ + { + "property": "result", + "operator": "=", + "value": "Not passed" + } + ] + } + ``` + Then click `Save`. + +6. Click `Create` to save the dashboard. + +After creating the dashboard, **group by** `Blueprint` and `Rule`. + +This configuration creates a view where action items are organized by the target blueprint and the specific rule that failed, making it easy to identify which entities have issues and what they are. diff --git a/docs/scorecards/manage-scorecards.md b/docs/scorecards/manage-scorecards.md index ce0c468cb4..baa49d187c 100644 --- a/docs/scorecards/manage-scorecards.md +++ b/docs/scorecards/manage-scorecards.md @@ -18,7 +18,19 @@ Port offers a variety of ways to create, edit and delete scorecards: -To create a scorecard from the UI: +To create a scorecard from the UI, you can use either one of the following methods: + +**Method 1: From the Scorecards page** + +1. Navigate to the [Software Catalog](https://app.getport.io/catalog) page. + +2. Go to the [Scorecards page](https://app.getport.io/_scorecards). + +3. Click the `+ Scorecard` button in the top right corner of the page. + +4. Follow the same steps as described in Method 2 below. The only difference is that you need to select the `Blueprint` you want to add the scorecard to. + +**Method 2: From the Data model page** 1. Go to the [Data model](https://app.getport.io/settings/data-model) page of your portal. @@ -29,7 +41,7 @@ To create a scorecard from the UI: 4. In the **Basic Details** tab, specify the scorecard's basic details: - `Title` - The scorecard's title. - - `Identifier` - The scorecard's identifier. + - `Identifier` - The scorecard's unique identifier (must be unique among all scorecards). - `Blueprint` - Set to the blueprint you selected. - `Filter` - Filter which entities the scorecard applies to. @@ -240,7 +252,7 @@ Here are some request examples that will create the Scorecard of Ownership on th After creating the Scorecards, you will see a new tab in the profile Entity page of each of your Blueprint's Entities, showing the various scorecards levels. -For example, we can [create the entity below](../build-your-software-catalog/sync-data-to-catalog/sync-data-to-catalog.md#creating-entities) +For example, we can [create the entity below](/build-your-software-catalog/sync-data-to-catalog/sync-data-to-catalog.md#entities): ```json showLineNumbers { @@ -255,13 +267,13 @@ For example, we can [create the entity below](../build-your-software-catalog/syn } ``` -And then look at the [specific page](https://app.getport.io/MicroserviceEntity?identifier=cart-service&activeTab=3) of this entity, on the scorecards tab +And then look at the [specific page](https://app.getport.io/MicroserviceEntity?identifier=cart-service&activeTab=3) of this entity, on the scorecards tab. -![Developer Portal Scorecards Tab](../../static/img/software-catalog/scorecard/tutorial/ScorecardsTab.png) + We can see that the `hasSlackChannel` rule passed because we provided one to that entity, while the `hasTeam` failed because we didn't provide any team. -Therefore the level of the entity is `Bronze` because it passed all the rules in the `Bronze` level (hasSlackChannel) +Therefore the level of the entity is `Bronze` because it passed all the rules in the `Bronze` level (hasSlackChannel). **Update scorecards** @@ -272,26 +284,31 @@ To update a scorecard you can use 2 different URLs: The request body will include the existing body of the Scorecard, after the desired updates to the existing Scorecard have been applied. +:::note +When using the multiple update Scorecards `https://api.getport.io/v1/blueprints/{blueprint_identifier}/scorecards` PUT request, keep in mind that you will see a new `id` property. This is used via Port to identify the Scorecard in order to be able to update its properties. +::: + **Delete scorecards** :::danger A Scorecard cannot be restored after deletion! ::: -- Make an HTTP PUT request and remove it from the array of the scorecards via the URL `https://api.getport.io/v1/blueprints/{blueprint_identifier}/scorecards` -- Make an HTTP DELETE request to the URL `https://api.getport.io/v1/blueprints/{blueprint_identifier}/scorecards/{scorecard_identifier}` the `scorecard_identifier` is the identifier of the scorecard we want to delete +- Make an HTTP PUT request and remove it from the array of the scorecards via the URL `https://api.getport.io/v1/blueprints/{blueprint_identifier}/scorecards`. +- Make an HTTP DELETE request to the URL `https://api.getport.io/v1/blueprints/{blueprint_identifier}/scorecards/{scorecard_identifier}` the `scorecard_identifier` is the identifier of the scorecard we want to delete. -:::note -When using the multiple update Scorecards `https://api.getport.io/v1/blueprints/{blueprint_identifier}/scorecards` PUT request, keep in mind that you will see a new `id` property. This is used via Port to identify the Scorecard in order to be able to update its properties +:::info Using entities API +Scorecards can be managed either with the dedicated **Scorecards API** mentioned above, or by using the standard **Entity API** endpoints: [Create](/api-reference/create-an-entity), [Update](/api-reference/update-an-entity), [Delete](/api-reference/delete-an-entity). ::: + **Create scorecards** -In order to create a scorecard from the [Terraform provider](../../build-your-software-catalog/custom-integration/iac/terraform/) , you will need to use the `port_scorecard` resource. +In order to create a scorecard from the [Terraform provider](/build-your-software-catalog/custom-integration/iac/terraform/) , you will need to use the `port_scorecard` resource. Here is an example of how to create an Ownership scorecard with the Terraform provider: @@ -353,13 +370,7 @@ In order to delete a scorecard using the Terraform provider, use the `terraform -## Scorecards as Blueprints - -Port allows you to manage scorecards as blueprints. -This feature enables you to create and manage scorecards using dedicated blueprints, allowing for rich customization, visualization and automation of your scorecards. - -To learn more, refer to the [scorecards as blueprints](/scorecards/scorecards-as-blueprints) page. - ## Next steps -[Dive into advanced operations on Scorecards with our API ➡️ ](/api-reference/port-api) \ No newline at end of file +- Explore [scorecard use-cases](/scorecards/examples/scorecard-use-cases) and [automation use-cases](/scorecards/examples/automation-use-cases) for examples you can implement in your environment. +- [Dive into advanced operations on Scorecards with our API ➡️ ](/api-reference/port-api) \ No newline at end of file diff --git a/docs/scorecards/manage-using-3rd-party-apps/_category_.json b/docs/scorecards/manage-using-3rd-party-apps/_category_.json index 0bcdd93f6b..fb9d8e2e7f 100644 --- a/docs/scorecards/manage-using-3rd-party-apps/_category_.json +++ b/docs/scorecards/manage-using-3rd-party-apps/_category_.json @@ -1,4 +1,4 @@ { "label": "Manage using 3rd party apps", - "position": 4 + "position": 5 } diff --git a/docs/scorecards/overview.md b/docs/scorecards/overview.md index 73b119a249..c59489f5e3 100644 --- a/docs/scorecards/overview.md +++ b/docs/scorecards/overview.md @@ -5,6 +5,8 @@ sidebar_label: Overview --- # Scorecards + +Scorecards help you ensure every component and process meets your engineering standards. They enable you to continuously monitor quality, security, and compliance across your software catalog, and easily act on insights through Port actions and automations. ## What is a Scorecard? diff --git a/docs/scorecards/scorecards-as-blueprints.md b/docs/scorecards/scorecards-as-blueprints.md deleted file mode 100644 index c63bf1e8d8..0000000000 --- a/docs/scorecards/scorecards-as-blueprints.md +++ /dev/null @@ -1,351 +0,0 @@ ---- -sidebar_position: 5 -title: Scorecards as blueprints -sidebar_label: Scorecards as blueprints ---- - -import PortTooltip from "/src/components/tooltip/tooltip.jsx" - -import Tabs from "@theme/Tabs" -import TabItem from "@theme/TabItem" - -:::info Feature rollout -This feature is being rolled out gradually and will be broadly available soon. -::: - -Port allows you to manage scorecards as blueprints. -This feature enables you to create and manage scorecards using dedicated blueprints, allowing for rich customization, visualization and automation of your scorecards. - -## Why manage scorecards as blueprints? - -With this powerful feature you can accomplish the following: - -1. **RBAC Management** - - Control who can create and modify scorecards and rules. - - Define which teams can view specific scorecard results. - - Manage permissions for rule creation and modification at a granular level. - -2. **Automations and Actions** - - Create workflows that trigger based on rule results. - - Set up automated notifications when entities change compliance levels. - - Build self-service actions to remediate failed rules. - - Integrate with external systems to sync scorecard data. - -3. **Reports and Dashboards** - - Build custom dashboards to visualize compliance across your organization. - - Track progress of entities through different levels. - - Generate reports on rule effectiveness and entity compliance. - - Monitor trends in rule results over time. - -## Overview - -After enabling `scorecards as blueprints`, three new blueprints will be created in your [data model](https://app.getport.io/settings/data-model): -- `Scorecard` - Represents a collection of rules and levels for evaluating entities. -- `Rule` - Defines specific criteria for evaluation. -- `Rule Result` - Stores the evaluation results for each entity. - -## Blueprint Structure - - - - - -The `Scorecard` blueprint contains the following properties: -| Name | Type | Description | -|------|------|-------------| -| Blueprint | string (format: blueprints) | The target blueprint whose entities will be evaluated | -| Levels | array of objects | An array of levels with titles and colors (e.g., Bronze, Silver, Gold) | -| Filter | object | Optional query to filter which entities should be evaluated | -| Rules Tested | number ([aggregation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property)) | Number of rule evaluations performed | -| Rules Passed | number ([aggregation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property)) | Number of successful rule evaluations | -| % of Rules Passed | number ([calculation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/calculation-property)) | Calculated percentage of passed rules | - -Relations: -| Name | Target Blueprint | Required | Many | Description | -|------|-----------------|----------|-------|-------------| -| - | - | - | - | No default relations | - - - - - -The `Rule` blueprint contains the following properties: -| Name | Type | Description | -|------|------|-------------| -| Level | string (enum) | The required level for this rule (must be one of the scorecard's defined levels) | -| Query | object | The evaluation criteria for entities | -| Rule Description | string | Optional explanation of the rule's logic | -| Entities Tested | number ([aggregation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property)) | Number of entities evaluated by this rule | -| Entities Passed | number ([aggregation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/aggregation-property)) | Number of entities that passed this rule | -| % of Entities Passed | number ([calculation](/build-your-software-catalog/customize-integrations/configure-data-model/setup-blueprint/properties/calculation-property)) | Calculated percentage of passed entities | - -Relations: -| Name | Target Blueprint | Required | Many | Description | -|------|-----------------|----------|-------|-------------| -| scorecard | Scorecard | true | false | The scorecard this rule belongs to | - - - - - -The `Rule result` blueprint contains the following properties: -| Name | Type | Description | -|------|------|-------------| -| Result | string (enum) | Whether the entity passed the rule ("Passed" or "Not passed") | -| Entity | string | The identifier of the evaluated entity | -| Result Last Change | string (date-time) | Timestamp of the last result change | -| Level | string (mirror) | Mirror property from the related rule | -| Scorecard | string (mirror) | Mirror property showing the parent scorecard title | -| Blueprint | string (mirror) | Mirror property showing the target blueprint | -| Entity Link | string (url) | Calculated URL to the evaluated entity | - -Relations: -| Name | Target Blueprint | Required | Many | Description | -|------|-----------------|----------|-------|-------------| -| rule | Rule | true | false | The rule that generated this result | -| [Blueprint Identifier] | [Dynamic] | false | false | Automatically created relation to the target blueprint when a new scorecard is created | - -:::info Dynamic Relations -When a new scorecard is created, Port automatically creates a relation in the Rule Result blueprint to the scorecard's target blueprint. For example, if you create a scorecard for the "service" blueprint, a new relation named "service" will be added to the Rule Result blueprint. -::: - - - - -## Important Notes - -1. The scorecard blueprints are protected and their core structure cannot be modified: - - Default properties cannot be changed or deleted. - - Required relations cannot be modified. - - The blueprints themselves cannot be deleted. - -2. You can extend the blueprints with: - - New properties. - - New non-required relations. - - Additional configurations that don't affect the core functionality. - -3. Rule Results are automatically generated and managed by Port: - - They cannot be created, deleted, or modified directly. - - You can update the custom properties you created for the rule results. - - Rule results are not searchable in the global search. - - They are updated automatically when rules are evaluated. - -## Validation Rules - -The system enforces several validation rules to maintain data integrity: - -1. Rule levels must match one of the levels defined in their parent scorecard. -2. Scorecard blueprint built-in relations cannot be renamed or modified. -3. Rule results maintain immutable core properties while allowing updates to custom properties. - -## Scorecard automation examples - -### Send a Slack/Teams message whenever a scorecard rule result is updated - -#### Automation definition - -By using the `ENTITY_UPDATED` trigger type, we can run custom logic whenever an entity of a specific type is updated. - -The following configuration will cause a message to be sent whenever a scorecard rule result is updated: - -
-Automation configuration (Click to expand) - -**Remember to change `github-org-name` and `github-repo-name` to your GitHub organization name and repository in the highlighted lines.** - -```json showLineNumbers -{ -"identifier": "ruleResultUpdated", -"title": "Rule result updated", -"trigger": { - "type": "automation", - "event": { - "type": "ENTITY_UPDATED", - "blueprintIdentifier": "_rule_result" - } -}, -"invocationMethod": { - "type": "GITHUB", - # highlight-start - "org": "github-org-name", - "repo": "github-repo-name", - # highlight-end - "workflow": "notify-rule-result-updated.yaml", - "workflowInputs": { - "rule_result_name": "{{ .event.context.entityIdentifier }}", - "entity_link": "{{ .event.diff.after.properties.entity_link }}" - }, - "reportWorkflowStatus": true -}, -"publish": true -} -``` -
- -* `invocationMethod.workflowInputs` is the payload to be passed to the GitHub workflow upon every execution. In this example, we pass the rule result's identifier and the link to the evaluated entity. - -* `invocationMethod.reportWorkflowStatus` is set to `true` to automatically update the action run in Port with the status of the GitHub workflow. - -#### Backend - GitHub workflow - -The `notify-rule-result-updated.yaml` workflow will contain the logic to send a Slack/Teams message. - -

Prerequisite - set up webhooks

- -The workflow requires a Slack webhook URL and/or a Microsoft Teams webhook URL to send the message. - -Slack: -1. To set up a Slack webhook, follow the instructions [here](https://api.slack.com/messaging/webhooks). -2. Once you have the webhook URL, add it as a secret in your GitHub repository named `SLACK_WEBHOOK_URL`. - -Microsoft Teams: -1. To set up a Microsoft Teams webhook, follow the instructions [here](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook). -2. Once you have the webhook URL, add it as a secret in your GitHub repository named `TEAMS_WEBHOOK_URL`. - -
-GitHub workflow (Click to expand) - -This workflow includes steps to send a message via **Slack** and **Microsoft Teams**. -**Use only the step(s) that apply to your use case.** - -```yaml showLineNumbers title="notify-rule-result-updated.yaml" -name: Notify when rule result is updated - -on: - workflow_dispatch: - inputs: - # Note that the inputs are the same as the payload (workflowInputs) defined in the automation - rule_result_name: - description: "The rule result's name" - required: true - type: string - entity_link: - description: "A link to the evaluated entity" - required: true - type: string - -jobs: - send_message: - runs-on: ubuntu-latest - steps: - - name: Send message to Slack - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - run: | - curl -X POST -H 'Content-type: application/json' --data '{"text":"The rule result ${{ inputs.rule_result_name }} has been updated. See evaluated entity: https://app.port.io${{ inputs.entity_link }}"}' $SLACK_WEBHOOK_URL - - - name: Send message to Microsoft Teams - env: - TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_WEBHOOK_URL }} - run: | - curl -H 'Content-Type: application/json' -d '{"text":"The rule result ${{ inputs.rule_result_name }} has been updated. See evaluated entity: https://app.port.io${{ inputs.entity_link }}"}' $TEAMS_WEBHOOK_URL -``` -
- ---- - -### Create a GitHub issue whenever a scorecard rule result is degraded - -#### Automation definition - -By using the `ENTITY_UPDATED` trigger type, we can run custom logic whenever an entity of a specific type is updated. - -The following configuration will create a GitHub issue whenever a scorecard rule result's `Result` property changes from `Passed` to `Not passed`: - -
-Automation configuration (Click to expand) - -**Remember to change `github-org-name` and `github-repo-name` to your GitHub organization name and repository in the highlighted lines.** - -```json showLineNumbers -{ - "identifier": "ruleResultDegraded", - "title": "Rule result degraded", - "trigger": { - "type": "automation", - "event": { - "type": "ENTITY_UPDATED", - "blueprintIdentifier": "_rule_result" - }, - "condition": { - "type": "JQ", - "expressions": [ - ".diff.before.properties.result == \"Passed\"", - ".diff.after.properties.result == \"Not passed\"" - ], - "combinator": "and" - } - }, - "invocationMethod": { - "type": "GITHUB", - # highlight-start - "org": "github-org-name", - "repo": "github-repo-name", - # highlight-end - "workflow": "create-issue-on-rule-degradation.yaml", - "workflowInputs": { - "rule_result_name": "{{ .event.context.entityIdentifier }}", - "entity_link": "{{ .event.diff.after.properties.entity_link }}" - }, - "reportWorkflowStatus": true - }, - "publish": true -} -``` -
- -* `trigger.condition` checks the rule result's `Result` property before and after the update. The automation will only run for rule results that have been degraded. - -* `invocationMethod.workflowInputs` is the payload to be passed to the GitHub workflow upon every execution. In this example, we pass the rule result's identifier and the link to the evaluated entity. - -* `invocationMethod.reportWorkflowStatus` is set to `true` to automatically update the action run in Port with the status of the GitHub workflow. - -#### Backend - GitHub workflow - -The `create-issue-on-rule-degradation.yaml` workflow will contain the logic to create a GitHub issue. - -
-GitHub workflow (Click to expand) - -```yaml showLineNumbers title="create-issue-on-rule-degradation.yaml" -name: Create issue when rule is degraded - -on: - workflow_dispatch: - inputs: - # Note that the inputs are the same as the payload (workflowInputs) defined in the automation - rule_result_name: - description: 'The rule result name' - required: true - type: string - entity_link: - description: 'A link to the evaluated entity' - required: true - type: string - -# Grant write access to issues so the workflow can create them -permissions: - contents: read - issues: write - -jobs: - send_message: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: create an issue - uses: dacbd/create-issue-action@main - with: - token: ${{ github.token }} - # By default, the issue will be created in the same repository as the workflow - repo: ${{ github.context.repo.repo}} - title: '${{ inputs.rule_result_name }} - degraded rule result' - body: | - The rule result ${{ inputs.rule_result_name }} has been degraded. - See evaluated entity: https://app.port.io${{ inputs.entity_link }} -``` -
\ No newline at end of file diff --git a/src/components/ProductPillars/ProductPillars.tsx b/src/components/ProductPillars/ProductPillars.tsx index 4dd61474c7..a63bb7f085 100644 --- a/src/components/ProductPillars/ProductPillars.tsx +++ b/src/components/ProductPillars/ProductPillars.tsx @@ -60,7 +60,7 @@ const ProductPillars: React.FC = () => { }, { title: 'Scorecards', - description: 'Define software standards and know they are met. Ensure quality, security, compliance, and velocity for all software catalog components.', + description: 'Ensure every component and process meets your engineering standards. Continuously monitor quality, security, and compliance across your software catalog, and easily act on insights through Port actions and automations.', demoUrl: 'https://showcase.port.io/serviceEntity?identifier=authentication&activeTab=2', icon: 'military_tech', }, diff --git a/static/img/scorecards/custom-scorecards-example.png b/static/img/scorecards/custom-scorecards-example.png index e737b6c660..1df33a6c42 100644 Binary files a/static/img/scorecards/custom-scorecards-example.png and b/static/img/scorecards/custom-scorecards-example.png differ diff --git a/static/img/software-catalog/scorecard/MyActionItemsDashboard.png b/static/img/software-catalog/scorecard/MyActionItemsDashboard.png new file mode 100644 index 0000000000..7669a0917a Binary files /dev/null and b/static/img/software-catalog/scorecard/MyActionItemsDashboard.png differ diff --git a/static/img/software-catalog/scorecard/catalogPageScorecardColumns.png b/static/img/software-catalog/scorecard/catalogPageScorecardColumns.png index 9f3d6cae07..cb4db9bdf8 100644 Binary files a/static/img/software-catalog/scorecard/catalogPageScorecardColumns.png and b/static/img/software-catalog/scorecard/catalogPageScorecardColumns.png differ diff --git a/static/img/software-catalog/scorecard/catalogRuleSummaries.png b/static/img/software-catalog/scorecard/catalogRuleSummaries.png index 469d659369..e9e3eb4aa3 100644 Binary files a/static/img/software-catalog/scorecard/catalogRuleSummaries.png and b/static/img/software-catalog/scorecard/catalogRuleSummaries.png differ diff --git a/static/img/software-catalog/scorecard/catalogViewScorecardsByTeam.png b/static/img/software-catalog/scorecard/catalogViewScorecardsByTeam.png index 9f1b0c1c5d..517ac26f55 100644 Binary files a/static/img/software-catalog/scorecard/catalogViewScorecardsByTeam.png and b/static/img/software-catalog/scorecard/catalogViewScorecardsByTeam.png differ diff --git a/static/img/software-catalog/scorecard/tutorial/ScorecardsTab.png b/static/img/software-catalog/scorecard/tutorial/ScorecardsTab.png index 5490ca53a8..55835d96b3 100644 Binary files a/static/img/software-catalog/scorecard/tutorial/ScorecardsTab.png and b/static/img/software-catalog/scorecard/tutorial/ScorecardsTab.png differ