Skip to content
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

Update documentation for mindev, and add some handy debugging methods #4548

Merged
merged 2 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 11 additions & 8 deletions cmd/dev/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# `mindev`

`mindev` is a command line utility to help you develop rules and profiles for Minder.
`mindev` is a command line utility to help you develop rules and profiles for
Minder.

## Building

Expand All @@ -22,17 +23,19 @@ mindev [command]
mindev ruletype test -e /path/to/entity -p /path/to/profile -r /path/to/rule
```

The entity is the path to the entity file, in case you're testing a rule type
that's targetted towards a repository, the YAML must match the repository
`ruletype test` is intended for testing a single rule; the entity definition
must match the rule's `def.in_entity` type. The tested entity is defined as a
set of YAML properties in the entity file; for example, if you're testing a rule
type that's targetted towards a repository, the YAML must match the repository
schema.

e.g.
e.g.

```yaml
name: my-repo
owner: my-org
repo_id: 123456789
clone_url: https://github.com/my-org/my-repo.git
github/repo_name: my-repo
github/repo_owner: my-org
github/repo_id: 123456789
github/clone_url: https://github.com/my-org/my-repo.git
```

The profile is the path to the profile file. This is needed to test the rule
Expand Down
2 changes: 1 addition & 1 deletion cmd/dev/app/rule_type/rttst.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func CmdTest() *cobra.Command {
testCmd.Flags().StringP("remediate-status", "", "", "The previous remediate status (optional)")
testCmd.Flags().StringP("remediate-metadata", "", "", "YAML file containing the remediate metadata (optional)")
testCmd.Flags().StringP("token", "t", "", "token to authenticate to the provider."+
"Can also be set via the AUTH_TOKEN environment variable.")
"Can also be set via the TEST_AUTH_TOKEN environment variable.")

if err := testCmd.MarkFlagRequired("rule-type"); err != nil {
fmt.Fprintf(os.Stderr, "Error marking flag as required: %s\n", err)
Expand Down
13 changes: 7 additions & 6 deletions cmd/dev/examples/pull_request.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.

url: https://api.github.com/repos/jakubtestorg/bad-npm/pulls/3
commitSHA: bd9958a63c9b95ccc2bc0cf1eef65a87529aed16
number: 3
repo_owner: jakubtestorg
repo_name: bad-npm
github/pull_url: https://api.github.com/repos/jakubtestorg/bad-npm/pulls/3
github/pull_sha: bd9958a63c9b95ccc2bc0cf1eef65a87529aed16
github/pull_number: 3
github/repo_owner: jakubtestorg
github/repo_name: bad-npm
github/pull_author_id: 144222806
github/pull_action: opened
patches:
- name: package-lock.json
patch_Url: https://github.com/jakubtestorg/bad-npm/raw/123/package-lock.json
authorID: 144222806
20 changes: 14 additions & 6 deletions cmd/dev/examples/repository.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,19 @@
# limitations under the License.

---
owner: stacklok
name: Demo-Repo-Go
repoId: 605597568
HookUrl:
clone_url: "https://github.com/stacklok/Demo-Repo-Go.git"
github/repo_name: demo-repo-go
github/repo_owner: stacklok
github/repo_id: 605597568
github/hook_url:
github/hook_id: 1234
github/deploy_url:
github/clone_url: "https://github.com/stacklok/demo-repo-go.git"
github/hook_type:
github/hook_name:
github/hook_uuid:
github/default_branch: main
github/license:
is_private: false
is_fork: false
CreatedAt: 2021-03-19T16:00:00Z
UpdatedAt: 2021-03-19T16:00:00Z
Registered: true
15 changes: 7 additions & 8 deletions cmd/dev/examples/versioned_artifact.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

artifact:
artifactId: 5482209
name: test
owner: jakubtestorg
repository: jakubtestorg/testrepo
type: CONTAINER
visibility: public
upstream_id: 5482209
github/name: test
github/type: CONTAINER
github/created_at: "2023-08-28T14:02:18Z"
github/repo_name: jakubtestorg/testrepo
github/owner: jakubtestorg
github/visibility: public
version:
createdAt: '2023-08-28T14:02:18Z'
github_workflow:
commit_sha: 542ff1ded187631de1077ef42c07a7b723ff0963
name: Docker
Expand Down
12 changes: 12 additions & 0 deletions internal/entities/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package models

import (
"fmt"

"github.com/google/uuid"

"github.com/stacklok/minder/internal/db"
Expand All @@ -33,6 +35,11 @@ type EntityInstance struct {
ProjectID uuid.UUID
}

// String implements fmt.Stringer for debugging purposes
func (ei EntityInstance) String() string {
return fmt.Sprintf("[%s]<%s>: %s / %s (%s)", ei.ProviderID, ei.Type, ei.ProjectID, ei.ID, ei.Name)
}

// EntityWithProperties represents an entity instance with properties
type EntityWithProperties struct {
Entity EntityInstance
Expand Down Expand Up @@ -61,6 +68,11 @@ func NewEntityWithPropertiesFromInstance(entity EntityInstance, props *propertie
}
}

// String implements fmt.Stringer for debugging purposes
func (ewp EntityWithProperties) String() string {
return fmt.Sprintf("ENTITY %s:\n%s", ewp.Entity, ewp.Properties)
}

// DbPropsToModel converts a slice of db.Property to a properties.Properties instance.
func DbPropsToModel(dbProps []db.Property) (*properties.Properties, error) {
propMap := make(map[string]any)
Expand Down
43 changes: 35 additions & 8 deletions internal/entities/properties/properties.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,20 @@ func (p *Property) AsInt64() (int64, error) {
return 0, fmt.Errorf("property is nil")
}

stringVal, err := unwrapTypedValue(p.value, typeInt64)
if err != nil {
return 0, fmt.Errorf("failed to get int64 value: %w", err)
switch value := p.value.Kind.(type) {
case *structpb.Value_NumberValue:
return int64(value.NumberValue), nil
case *structpb.Value_StringValue:
return strconv.ParseInt(value.StringValue, 10, 64)
case *structpb.Value_StructValue:
stringVal, err := unwrapTypedValue(p.value, typeInt64)
if err != nil {
return 0, fmt.Errorf("failed to get int64 value: %w", err)
}
return strconv.ParseInt(stringVal, 10, 64)
default:
return 0, fmt.Errorf("failed to get int64 value from %T", value)
}
return strconv.ParseInt(stringVal, 10, 64)
}

// GetInt64 returns the int64 value, or 0 if the value is not an int64
Expand All @@ -171,11 +180,20 @@ func (p *Property) AsUint64() (uint64, error) {
return 0, fmt.Errorf("property is nil")
}

stringVal, err := unwrapTypedValue(p.value, typeUint64)
if err != nil {
return 0, fmt.Errorf("failed to get uint64 value: %w", err)
switch value := p.value.Kind.(type) {
case *structpb.Value_NumberValue:
return uint64(value.NumberValue), nil
case *structpb.Value_StringValue:
return strconv.ParseUint(value.StringValue, 10, 64)
case *structpb.Value_StructValue:
stringVal, err := unwrapTypedValue(p.value, typeUint64)
if err != nil {
return 0, fmt.Errorf("failed to get uint64 value: %w", err)
}
return strconv.ParseUint(stringVal, 10, 64)
default:
return 0, fmt.Errorf("failed to get uint64 value from %T", value)
}
return strconv.ParseUint(stringVal, 10, 64)
}

// GetUint64 returns the uint64 value, or 0 if the value is not an uint64
Expand Down Expand Up @@ -280,6 +298,15 @@ func (p *Properties) Iterate() iter.Seq2[string, *Property] {
}
}

// String implements the fmt.Stringer interface, for debugging purposes
func (p *Properties) String() string {
data := make([]string, 0, p.props.Size())
for k, v := range p.Iterate() {
data = append(data, fmt.Sprintf("%s: %v (%T)", k, v.RawValue(), v.RawValue()))
}
return strings.Join(data, "\n")
}

// PropertyFilter is a function that filters properties
type PropertyFilter func(key string, prop *Property) bool

Expand Down
66 changes: 56 additions & 10 deletions internal/entities/properties/properties_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,11 @@ func TestInt64Getters(t *testing.T) {
t.Parallel()

input := map[string]any{
"id": 1,
"is_private": true,
"count": int64(5),
"large": int64(math.MaxInt64),
"id": 1,
"is_private": true,
"count": int64(5),
"large": int64(math.MaxInt64),
"from_string": "2",
}

scenarios := []struct {
Expand Down Expand Up @@ -221,7 +222,7 @@ func TestInt64Getters(t *testing.T) {
{
name: "AsInt64 non-int64 property",
propName: "is_private",
errString: "failed to get int64 value: value is not a map",
errString: "failed to get int64 value",
},
{
name: "GetInt64 non-int64 property",
Expand All @@ -240,6 +241,28 @@ func TestInt64Getters(t *testing.T) {
expValue: math.MaxInt64,
callGet: true,
},
{
name: "AsUint64 from int",
propName: "id",
expValue: 1,
},
{
name: "AsUint64 from int",
propName: "id",
expValue: 1,
callGet: true,
},
{
name: "AsUint64 from string",
propName: "from_string",
expValue: 2,
},
{
name: "AsUint64 from string",
propName: "from_string",
expValue: 2,
callGet: true,
},
}

for _, s := range scenarios {
Expand Down Expand Up @@ -271,10 +294,11 @@ func TestUint64Getters(t *testing.T) {
t.Parallel()

input := map[string]any{
"id": 1,
"is_private": true,
"count": uint64(5),
"large": uint64(math.MaxUint64),
"id": 1,
"is_private": true,
"count": uint64(5),
"large": uint64(math.MaxUint64),
"from_string": "2",
}

scenarios := []struct {
Expand Down Expand Up @@ -309,7 +333,7 @@ func TestUint64Getters(t *testing.T) {
{
name: "AsUint64 non-uint64 property",
propName: "is_private",
errString: "failed to get uint64 value: value is not a map",
errString: "failed to get uint64 value",
},
{
name: "GetUint64 non-uint64 property",
Expand All @@ -328,6 +352,28 @@ func TestUint64Getters(t *testing.T) {
expValue: math.MaxUint64,
callGet: true,
},
{
name: "AsUint64 from int",
propName: "id",
expValue: 1,
},
{
name: "AsUint64 from int",
propName: "id",
expValue: 1,
callGet: true,
},
{
name: "AsUint64 from string",
propName: "from_string",
expValue: 2,
},
{
name: "AsUint64 from string",
propName: "from_string",
expValue: 2,
callGet: true,
},
}

for _, s := range scenarios {
Expand Down