Skip to content

Commit 0976edf

Browse files
committed
resolve merge conflicts
2 parents dffde7c + 751a509 commit 0976edf

50 files changed

Lines changed: 2524 additions & 541 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.chainloop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# This can indicate the next version and by default it will be marked as pre-release
2-
projectVersion: v1.31.0
2+
projectVersion: v1.35.0
33

44
# Experimental feature used by Chainloop labs shared workflow https://github.com/chainloop-dev/labs
55
# It maps the material names with location in disk so they get automatically attested

app/cli/cmd/organization_member_delete.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ import (
2525

2626
// Get the membership entry associated to the current user for the given organization
2727
func loadMembershipCurrentOrg(ctx context.Context, membershipID string) (*action.MembershipItem, error) {
28-
memberships, err := action.NewMembershipList(actionOpts).ListMembers(ctx)
28+
res, err := action.NewMembershipList(actionOpts).ListMembers(ctx, 1, 1, &action.ListMembersOpts{MembershipID: &membershipID})
2929
if err != nil {
3030
return nil, fmt.Errorf("listing memberships: %w", err)
3131
}
3232

33-
for _, m := range memberships {
33+
for _, m := range res.Memberships {
3434
if m.ID == membershipID {
3535
return m, nil
3636
}

app/cli/cmd/organization_member_list.go

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,109 @@ import (
1919
"fmt"
2020
"time"
2121

22+
"github.com/chainloop-dev/chainloop/app/cli/cmd/options"
2223
"github.com/chainloop-dev/chainloop/app/cli/internal/action"
24+
2325
"github.com/jedib0t/go-pretty/v6/table"
2426
"github.com/spf13/cobra"
2527
)
2628

2729
func newOrganizationMemberList() *cobra.Command {
30+
var (
31+
paginationOpts = &options.OffsetPaginationOpts{}
32+
name string
33+
email string
34+
role string
35+
)
36+
2837
cmd := &cobra.Command{
2938
Use: "list",
3039
Aliases: []string{"ls"},
3140
Short: "List the members of the current organization",
41+
Example: ` # Let the default pagination apply
42+
chainloop organization member list
43+
44+
# Specify the page and page size
45+
chainloop organization member list --page 2 --limit 10
46+
47+
# Filter by name
48+
chainloop organization member list --name alice
49+
50+
# Filter by email
51+
chainloop organization member list --email alice@example.com
52+
53+
# Filter by role
54+
chainloop organization member list --role admin
55+
56+
# Combine filters and pagination
57+
chainloop organization member list --role admin --page 2 --limit 5
58+
`,
59+
PreRunE: func(_ *cobra.Command, _ []string) error {
60+
if paginationOpts.Page < 1 {
61+
return fmt.Errorf("--page must be greater or equal than 1")
62+
}
63+
if paginationOpts.Limit < 1 {
64+
return fmt.Errorf("--limit must be greater or equal than 1")
65+
}
66+
67+
return nil
68+
},
3269
RunE: func(cmd *cobra.Command, args []string) error {
33-
res, err := action.NewMembershipList(actionOpts).ListMembers(cmd.Context())
70+
opts := &action.ListMembersOpts{}
71+
72+
switch {
73+
case name != "":
74+
opts.Name = &name
75+
case email != "":
76+
opts.Email = &email
77+
case role != "":
78+
opts.Role = &role
79+
}
80+
81+
res, err := action.NewMembershipList(actionOpts).ListMembers(cmd.Context(), paginationOpts.Page, paginationOpts.Limit, opts)
3482
if err != nil {
3583
return err
3684
}
3785

38-
return encodeOutput(res, orgMembershipsTableOutput)
86+
if err := encodeOutput(res, orgMembershipsTableOutput); err != nil {
87+
return err
88+
}
89+
90+
pgResponse := res.PaginationMeta
91+
92+
if pgResponse.TotalPages >= paginationOpts.Page {
93+
inPage := min(paginationOpts.Limit, len(res.Memberships))
94+
lowerBound := (paginationOpts.Page - 1) * paginationOpts.Limit
95+
logger.Info().Msg(fmt.Sprintf("Showing [%d-%d] out of %d", lowerBound+1, lowerBound+inPage, pgResponse.TotalCount))
96+
}
97+
98+
if pgResponse.TotalCount > pgResponse.Page*pgResponse.PageSize {
99+
logger.Info().Msg(fmt.Sprintf("Next page available: %d", pgResponse.Page+1))
100+
}
101+
102+
return nil
39103
},
40104
}
41105

106+
cmd.Flags().StringVar(&name, "name", "", "Filter by member name or last name")
107+
cmd.Flags().StringVar(&email, "email", "", "Filter by member email")
108+
cmd.Flags().StringVar(&role, "role", "", fmt.Sprintf("Role of the user in the organization, available %s", action.AvailableRoles[:3]))
109+
paginationOpts.AddFlags(cmd)
110+
42111
return cmd
43112
}
44113

45-
func orgMembershipsTableOutput(items []*action.MembershipItem) error {
46-
if len(items) == 0 {
47-
fmt.Println(UserWithNoOrganizationMsg)
48-
return nil
49-
}
50-
114+
func orgMembershipsTableOutput(res *action.ListMembershipResult) error {
51115
t := newTableWriter()
52116
t.AppendHeader(table.Row{"ID", "Email", "Role", "Joined At"})
53117

54-
for _, i := range items {
55-
t.AppendRow(table.Row{i.ID, i.User.PrintUserProfileWithEmail(), i.Role, i.CreatedAt.Format(time.RFC822)})
118+
for _, m := range res.Memberships {
119+
t.AppendRow(table.Row{
120+
m.ID,
121+
m.User.PrintUserProfileWithEmail(),
122+
m.Role,
123+
m.CreatedAt.Format(time.RFC822),
124+
})
56125
t.AppendSeparator()
57126
}
58127

app/cli/cmd/organization_member_update.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func newOrganizationMemberUpdateCmd() *cobra.Command {
4646
return err
4747
}
4848

49-
return encodeOutput([]*action.MembershipItem{res}, orgMembershipsTableOutput)
49+
return encodeOutput(&action.ListMembershipResult{Memberships: []*action.MembershipItem{res}}, orgMembershipsTableOutput)
5050
},
5151
}
5252

app/cli/cmd/output.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ type tabulatedData interface {
5353
[]*action.OrgInvitationItem |
5454
*action.APITokenItem |
5555
[]*action.APITokenItem |
56-
*action.AttestationStatusMaterial
56+
*action.AttestationStatusMaterial |
57+
*action.ListMembershipResult
5758
}
5859

5960
var ErrOutputFormatNotImplemented = errors.New("format not implemented")

app/cli/cmd/policy_develop.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,6 @@ Refer to https://docs.chainloop.dev/guides/custom-policies
2828
`,
2929
}
3030

31-
cmd.AddCommand(newPolicyDevelopEvalCmd())
31+
cmd.AddCommand(newPolicyDevelopInitCmd(), newPolicyDevelopEvalCmd())
3232
return cmd
3333
}

app/cli/cmd/policy_develop_init.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//
2+
// Copyright 2025 The Chainloop Authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package cmd
17+
18+
import (
19+
"fmt"
20+
21+
"github.com/chainloop-dev/chainloop/app/cli/internal/action"
22+
"github.com/spf13/cobra"
23+
)
24+
25+
func newPolicyDevelopInitCmd() *cobra.Command {
26+
var (
27+
force bool
28+
embedded bool
29+
name string
30+
description string
31+
directory string
32+
)
33+
34+
cmd := &cobra.Command{
35+
Use: "init",
36+
Short: "Initialize a new policy",
37+
Long: `Initialize a new policy by creating template policy files in the specified directory.
38+
By default, it creates chainloop-policy.yaml and chainloop-policy.rego files.`,
39+
Example: `
40+
# Initialize in current directory with separate files
41+
chainloop policy develop init
42+
43+
# Initialize in specific directory with embedded format and policy name
44+
chainloop policy develop init --directory ./policies --embedded --name mypolicy`,
45+
RunE: func(_ *cobra.Command, _ []string) error {
46+
if directory == "" {
47+
directory = "."
48+
}
49+
opts := &action.PolicyInitOpts{
50+
Force: force,
51+
Embedded: embedded,
52+
Name: name,
53+
Description: description,
54+
Directory: directory,
55+
}
56+
57+
policyInit, err := action.NewPolicyInit(opts, actionOpts)
58+
if err != nil {
59+
return fmt.Errorf("failed to initialize policy: %w", err)
60+
}
61+
62+
if err := policyInit.Run(); err != nil {
63+
return newGracefulError(err)
64+
}
65+
66+
logger.Info().Msg("Initialized policy files")
67+
68+
return nil
69+
},
70+
}
71+
72+
cmd.Flags().BoolVarP(&force, "force", "f", false, "overwrite existing files")
73+
cmd.Flags().BoolVar(&embedded, "embedded", false, "initialize an embedded policy (single YAML file)")
74+
cmd.Flags().StringVar(&name, "name", "", "name of the policy")
75+
cmd.Flags().StringVar(&description, "description", "", "description of the policy")
76+
cmd.Flags().StringVar(&directory, "directory", "", "directory for policy")
77+
return cmd
78+
}

app/cli/documentation/cli-reference.mdx

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2573,10 +2573,38 @@ List the members of the current organization
25732573
chainloop organization member list [flags]
25742574
```
25752575

2576+
Examples
2577+
2578+
```
2579+
Let the default pagination apply
2580+
chainloop organization member list
2581+
2582+
Specify the page and page size
2583+
chainloop organization member list --page 2 --limit 10
2584+
2585+
Filter by name
2586+
chainloop organization member list --name alice
2587+
2588+
Filter by email
2589+
chainloop organization member list --email alice@example.com
2590+
2591+
Filter by role
2592+
chainloop organization member list --role admin
2593+
2594+
Combine filters and pagination
2595+
chainloop organization member list --role admin --page 2 --limit 5
2596+
2597+
```
2598+
25762599
Options
25772600

25782601
```
2579-
-h, --help help for list
2602+
--email string Filter by member email
2603+
-h, --help help for list
2604+
--limit int number of items to show (default 50)
2605+
--name string Filter by member name or last name
2606+
--page int page number (default 1)
2607+
--role string Role of the user in the organization, available admin, owner, viewer
25802608
```
25812609

25822610
Options inherited from parent commands
@@ -2839,6 +2867,57 @@ Options inherited from parent commands
28392867
-y, --yes Skip confirmation
28402868
```
28412869

2870+
#### chainloop policy develop init
2871+
2872+
Initialize a new policy
2873+
2874+
Synopsis
2875+
2876+
Initialize a new policy by creating template policy files in the specified directory.
2877+
By default, it creates chainloop-policy.yaml and chainloop-policy.rego files.
2878+
2879+
```
2880+
chainloop policy develop init [flags]
2881+
```
2882+
2883+
Examples
2884+
2885+
```
2886+
2887+
Initialize in current directory with separate files
2888+
chainloop policy develop init
2889+
2890+
Initialize in specific directory with embedded format and policy name
2891+
chainloop policy develop init --directory ./policies --embedded --name mypolicy
2892+
```
2893+
2894+
Options
2895+
2896+
```
2897+
--description string description of the policy
2898+
--directory string directory for policy
2899+
--embedded initialize an embedded policy (single YAML file)
2900+
-f, --force overwrite existing files
2901+
-h, --help help for init
2902+
--name string name of the policy
2903+
```
2904+
2905+
Options inherited from parent commands
2906+
2907+
```
2908+
--artifact-cas string URL for the Artifacts Content Addressable Storage API ($CHAINLOOP_ARTIFACT_CAS_API) (default "api.cas.chainloop.dev:443")
2909+
--artifact-cas-ca string CUSTOM CA file for the Artifacts CAS API (optional) ($CHAINLOOP_ARTIFACT_CAS_API_CA)
2910+
-c, --config string Path to an existing config file (default is $HOME/.config/chainloop/config.toml)
2911+
--control-plane string URL for the Control Plane API ($CHAINLOOP_CONTROL_PLANE_API) (default "api.cp.chainloop.dev:443")
2912+
--control-plane-ca string CUSTOM CA file for the Control Plane API (optional) ($CHAINLOOP_CONTROL_PLANE_API_CA)
2913+
--debug Enable debug/verbose logging mode
2914+
-i, --insecure Skip TLS transport during connection to the control plane ($CHAINLOOP_API_INSECURE)
2915+
-n, --org string organization name
2916+
-o, --output string Output format, valid options are json and table (default "table")
2917+
-t, --token string API token. NOTE: Alternatively use the env variable CHAINLOOP_TOKEN
2918+
-y, --yes Skip confirmation
2919+
```
2920+
28422921
### chainloop policy help
28432922

28442923
Help about any command

0 commit comments

Comments
 (0)