Skip to content

feat: extensions readme generator #191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/cli/cmd/available_integration_describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"sort"

"github.com/chainloop-dev/chainloop/app/cli/internal/action"
"github.com/chainloop-dev/chainloop/app/controlplane/extensions/sdk/v1"
"github.com/jedib0t/go-pretty/v6/table"
"github.com/jedib0t/go-pretty/v6/text"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -92,7 +93,7 @@ func availableIntegrationDescribeTableOutput(items []*action.AvailableIntegratio
}

// render de-normalized schema format
func renderSchemaTable(tableTitle string, properties action.SchemaPropertiesMap) error {
func renderSchemaTable(tableTitle string, properties sdk.SchemaPropertiesMap) error {
if len(properties) == 0 {
return nil
}
Expand Down
3 changes: 2 additions & 1 deletion app/cli/cmd/registered_integration_add.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strings"

"github.com/chainloop-dev/chainloop/app/cli/internal/action"
"github.com/chainloop-dev/chainloop/app/controlplane/extensions/sdk/v1"
"github.com/santhosh-tekuri/jsonschema/v5"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -98,7 +99,7 @@ func parseAndValidateOpts(opts []string, schema *action.JSONSchema) (map[string]
// parseKeyValOpts performs two steps
// 1 - Split the options into key/value pairs
// 2 - Cast the values to the expected type defined in the schema
func parseKeyValOpts(opts []string, propertiesMap action.SchemaPropertiesMap) (map[string]any, error) {
func parseKeyValOpts(opts []string, propertiesMap sdk.SchemaPropertiesMap) (map[string]any, error) {
// 1 - Split the options into key/value pairs
var options = make(map[string]any)
for _, opt := range opts {
Expand Down
113 changes: 9 additions & 104 deletions app/cli/internal/action/available_integration_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@
package action

import (
"bytes"
"context"
"errors"
"fmt"
"sort"

pb "github.com/chainloop-dev/chainloop/app/controlplane/api/controlplane/v1"
"github.com/chainloop-dev/chainloop/app/controlplane/extensions/sdk/v1"
"github.com/santhosh-tekuri/jsonschema/v5"
)

Expand All @@ -45,22 +44,8 @@ type JSONSchema struct {
Raw string `json:"schema"`
// Parsed schema so it can be used for validation or other purposes
// It's not shown in the json output
Parsed *jsonschema.Schema `json:"-"`
Properties SchemaPropertiesMap `json:"-"`
}

type SchemaPropertiesMap map[string]*SchemaProperty
type SchemaProperty struct {
// Name of the property
Name string
// optional description
Description string
// Type of the property (string, boolean, number)
Type string
// If the property is required
Required bool
// Optional format (email, host)
Format string
Parsed *jsonschema.Schema `json:"-"`
Properties sdk.SchemaPropertiesMap `json:"-"`
}

func NewAvailableIntegrationList(cfg *ActionsOpts) *AvailableIntegrationList {
Expand Down Expand Up @@ -107,24 +92,24 @@ func pbAvailableIntegrationItemToAction(in *pb.IntegrationAvailableItem) (*Avail

// Parse the schemas so they can be used for validation or other purposes
var err error
i.Registration.Parsed, err = compileJSONSchema(foType.GetRegistrationSchema())
i.Registration.Parsed, err = sdk.CompileJSONSchema(foType.GetRegistrationSchema())
if err != nil {
return nil, fmt.Errorf("failed to compile registration schema: %w", err)
}

i.Attachment.Parsed, err = compileJSONSchema(foType.GetAttachmentSchema())
i.Attachment.Parsed, err = sdk.CompileJSONSchema(foType.GetAttachmentSchema())
if err != nil {
return nil, fmt.Errorf("failed to compile registration schema: %w", err)
}

// Calculate the properties map
i.Registration.Properties = make(SchemaPropertiesMap)
if err := calculatePropertiesMap(i.Registration.Parsed, &i.Registration.Properties); err != nil {
i.Registration.Properties = make(sdk.SchemaPropertiesMap)
if err := sdk.CalculatePropertiesMap(i.Registration.Parsed, &i.Registration.Properties); err != nil {
return nil, fmt.Errorf("failed to calculate registration properties: %w", err)
}

i.Attachment.Properties = make(SchemaPropertiesMap)
if err := calculatePropertiesMap(i.Attachment.Parsed, &i.Attachment.Properties); err != nil {
i.Attachment.Properties = make(sdk.SchemaPropertiesMap)
if err := sdk.CalculatePropertiesMap(i.Attachment.Parsed, &i.Attachment.Properties); err != nil {
return nil, fmt.Errorf("failed to calculate attachment properties: %w", err)
}

Expand All @@ -133,83 +118,3 @@ func pbAvailableIntegrationItemToAction(in *pb.IntegrationAvailableItem) (*Avail

return i, nil
}

func compileJSONSchema(in []byte) (*jsonschema.Schema, error) {
// Parse the schemas
compiler := jsonschema.NewCompiler()
// Enable format validation
compiler.AssertFormat = true
// Show description
compiler.ExtractAnnotations = true

if err := compiler.AddResource("schema.json", bytes.NewReader(in)); err != nil {
return nil, fmt.Errorf("failed to compile schema: %w", err)
}

return compiler.Compile("schema.json")
}

// calculate a map with all the properties of a schema
func calculatePropertiesMap(s *jsonschema.Schema, m *SchemaPropertiesMap) error {
if m == nil {
return nil
}

// Schema with reference
if s.Ref != nil {
return calculatePropertiesMap(s.Ref, m)
}

// Appended schemas
if s.AllOf != nil {
for _, s := range s.AllOf {
if err := calculatePropertiesMap(s, m); err != nil {
return err
}
}
}

if s.Properties != nil {
requiredMap := make(map[string]bool)
for _, r := range s.Required {
requiredMap[r] = true
}

for k, v := range s.Properties {
if err := calculatePropertiesMap(v, m); err != nil {
return err
}

var required = requiredMap[k]
(*m)[k] = &SchemaProperty{
Name: k,
Type: v.Types[0],
Required: required,
Description: v.Description,
Format: v.Format,
}
}
}

// We return the map sorted
// This is not strictly necessary but it makes the output more readable
// and it's easier to test

// Sort the keys
keys := make([]string, 0, len(*m))
for k := range *m {
keys = append(keys, k)
}

sort.Strings(keys)

// Create a new map with the sorted keys
newMap := make(SchemaPropertiesMap)
for _, k := range keys {
newMap[k] = (*m)[k]
}

*m = newMap

return nil
}
93 changes: 0 additions & 93 deletions app/cli/internal/action/available_integration_list_test.go

This file was deleted.

84 changes: 84 additions & 0 deletions app/controlplane/extensions/core/dependency-track/v1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
### Dependency-Track fan-out Extension

This extension implements sending cycloneDX Software Bill of Materials (SBOM) to Dependency-Track.

See https://docs.chainloop.dev/guides/dependency-track/


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we have a separate section with an info on which materials, attestations are supported?

### Supported metadata
The following metadata are supported by this extension:

Materials: CycloneDX
Attestations:  unsupported

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this could be used as a baseline. The scope was just schema for now. but I could see value in generating description input types and so on. Should we do it in another diff?

## Registration Input Schema

|Field|Type|Required|Description|
|---|---|---|---|
|allowAutoCreate|boolean|no|Support of creating projects on demand|
|apiKey|string|yes|The API key to use for authentication|
|instanceURI|string (uri)|yes|The URL of the Dependency-Track instance|

```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/chainloop-dev/chainloop/app/controlplane/extensions/core/dependency-track/v1/registration-request",
"properties": {
"instanceURI": {
"type": "string",
"format": "uri",
"description": "The URL of the Dependency-Track instance"
},
"apiKey": {
"type": "string",
"description": "The API key to use for authentication"
},
"allowAutoCreate": {
"type": "boolean",
"description": "Support of creating projects on demand"
}
},
"additionalProperties": false,
"type": "object",
"required": [
"instanceURI",
"apiKey"
]
}
```

## Attachment Input Schema

|Field|Type|Required|Description|
|---|---|---|---|
|projectID|string|no|The ID of the existing project to send the SBOMs to|
|projectName|string|no|The name of the project to create and send the SBOMs to|

```json
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://github.com/chainloop-dev/chainloop/app/controlplane/extensions/core/dependency-track/v1/attachment-request",
"oneOf": [
{
"required": [
"projectID"
],
"title": "projectID"
},
{
"required": [
"projectName"
],
"title": "projectName"
}
],
"properties": {
"projectID": {
"type": "string",
"minLength": 1,
"description": "The ID of the existing project to send the SBOMs to"
},
"projectName": {
"type": "string",
"minLength": 1,
"description": "The name of the project to create and send the SBOMs to"
}
},
"additionalProperties": false,
"type": "object"
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"fmt"

schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/app/controlplane/extensions/core/dependencytrack/v1/client"
"github.com/chainloop-dev/chainloop/app/controlplane/extensions/core/dependency-track/v1/client"
"github.com/chainloop-dev/chainloop/app/controlplane/extensions/sdk/v1"
"github.com/go-kratos/kratos/v2/log"
)
Expand Down Expand Up @@ -62,7 +62,7 @@ const description = "Send CycloneDX SBOMs to your Dependency-Track instance"
func New(l log.Logger) (sdk.FanOut, error) {
base, err := sdk.NewFanOut(
&sdk.NewParams{
ID: "dependencytrack",
ID: "dependency-track",
Version: "0.2",
Description: description,
Logger: l,
Expand Down
5 changes: 0 additions & 5 deletions app/controlplane/extensions/core/dependencytrack/v1/README.md

This file was deleted.

Loading