Skip to content

Commit d0e5fe6

Browse files
Fix provisioning for groups and vaults, update documentation
1 parent 623880c commit d0e5fe6

File tree

9 files changed

+306
-76
lines changed

9 files changed

+306
-76
lines changed

.github/workflows/ci.yaml

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
- name: Install Go
88
uses: actions/setup-go@v4
99
with:
10-
go-version: 1.22.x
10+
go-version: 1.23.x
1111
- name: Checkout code
1212
uses: actions/checkout@v3
1313
- name: Run linters
@@ -18,7 +18,7 @@ jobs:
1818
go-test:
1919
strategy:
2020
matrix:
21-
go-version: [1.22.x]
21+
go-version: [1.23.x]
2222
platform: [ubuntu-latest]
2323
runs-on: ${{ matrix.platform }}
2424
steps:
@@ -35,4 +35,82 @@ jobs:
3535
if: always()
3636
uses: guyarb/[email protected]
3737
with:
38-
test-results: test.json
38+
test-results: test.json
39+
40+
test:
41+
runs-on: ubuntu-latest
42+
env:
43+
BATON_LOG_LEVEL: debug
44+
ONE_PASSWORD_EMAIL: ${{ secrets.EMAIL }}
45+
ONE_PASSWORD_PASSWORD: ${{ secrets.PASSWORD }}
46+
ONE_PASSWORD_SECRET_KEY: ${{ secrets.SECRET_KEY }}
47+
ONE_PASSWORD_ACCOUNT_ADDRESS: ${{ secrets.ADDRESS }}
48+
GROUP_ENTITLEMENT: ${{ vars.GROUP_ENTITLEMENT }}
49+
GROUP_GRANT: ${{ vars.GROUP_GRANT }}
50+
PRINCIPAL: ${{ vars.PRINCIPAL }}
51+
VAULT_ENTITLEMENT: ${{ vars.VAULT_ENTITLEMENT }}
52+
VAULT_GRANT: ${{ vars.VAULT_GRANT }}
53+
PRINCIPAL_TYPE: ${{ vars.PRINCIPAL_TYPE }}
54+
55+
steps:
56+
- name: Set up Go
57+
uses: actions/setup-go@v4
58+
with:
59+
go-version: 1.23.x
60+
61+
- name: Checkout code
62+
uses: actions/checkout@v4
63+
64+
- name: Install 1Password CLI
65+
run: |
66+
curl -sS https://downloads.1password.com/linux/keys/1password.asc | sudo gpg --dearmor -o /usr/share/keyrings/1password-archive-keyring.gpg
67+
echo 'deb [signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/amd64 stable main' | sudo tee /etc/apt/sources.list.d/1password.list
68+
sudo apt update
69+
sudo apt install -y 1password-cli
70+
op --version
71+
72+
- name: Build baton-1password
73+
run: go build ./cmd/baton-1password
74+
75+
- name: Run baton-1password (generate sync.c1z)
76+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }}
77+
78+
- name: Install baton
79+
run: ./scripts/get-baton.sh && mv baton /usr/local/bin
80+
81+
- name: Grant entitlement Group
82+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }} --grant-entitlement=${{ env.GROUP_ENTITLEMENT }} --grant-principal=${{ env.PRINCIPAL }} --grant-principal-type=${{ env.PRINCIPAL_TYPE }}
83+
84+
- name: Re-sync the data from 1password
85+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }}
86+
87+
- name: Check grants was granted
88+
run: baton grants --entitlement="${{ env.GROUP_ENTITLEMENT }}" --output-format=json | jq --exit-status '.grants[].principal.id.resource == "${{ env.PRINCIPAL }}"' | grep true
89+
90+
- name: Revoke grants Group
91+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }} --revoke-grant="${{env.GROUP_GRANT}}"
92+
93+
- name: Re-sync the data from 1password
94+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }}
95+
96+
- name: Check grant was revoked
97+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }} && baton grants --entitlement="${{ env.GROUP_ENTITLEMENT }}" --output-format=json | jq --exit-status 'if .grants then .grants[]?.principal.id.resource != "${{ env.PRINCIPAL }}" else . end'
98+
99+
- name: Grant entitlement Vault
100+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }} --grant-entitlement=${{ env.VAULT_ENTITLEMENT }} --grant-principal=${{ env.PRINCIPAL }} --grant-principal-type=${{ env.PRINCIPAL_TYPE }}
101+
102+
- name: Re-sync the data from 1password
103+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }}
104+
105+
- name: Check grants was granted
106+
run: baton grants --entitlement="${{ env.PROJECT_ENTITLEMENT }}" --output-format=json | jq --exit-status '.grants[].principal.id.resource == "${{ env.PRINCIPAL }}"' | grep true
107+
108+
- name: Revoke grants Vault
109+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }} --revoke-grant="${{env.VAULT_GRANT}}"
110+
111+
- name: Re-sync the data from 1password
112+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }}
113+
114+
- name: Check grant was revoked
115+
run: ./baton-1password --password=${{ env.ONE_PASSWORD_PASSWORD }} --email=${{ env.ONE_PASSWORD_EMAIL }} --secret-key=${{ env.ONE_PASSWORD_SECRET_KEY }} --address=${{ env.ONE_PASSWORD_ACCOUNT_ADDRESS }} && baton grants --entitlement="${{ env.PROJECT_ENTITLEMENT }}" --output-format=json | jq --exit-status 'if .grants then .grants[]?.principal.id.resource != "${{ env.PRINCIPAL }}" else . end'
116+

.github/workflows/main.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
- name: Install Go
1111
uses: actions/setup-go@v4
1212
with:
13-
go-version: 1.22.x
13+
go-version: 1.23.x
1414
- name: Checkout code
1515
uses: actions/checkout@v3
1616
- name: Run linters
@@ -21,7 +21,7 @@ jobs:
2121
go-test:
2222
strategy:
2323
matrix:
24-
go-version: [ 1.22.x ]
24+
go-version: [ 1.23.x ]
2525
platform: [ ubuntu-latest ]
2626
runs-on: ${{ matrix.platform }}
2727
steps:

.github/workflows/release.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Set up Go
1717
uses: actions/setup-go@v4
1818
with:
19-
go-version: 1.22.x
19+
go-version: 1.23.x
2020
- name: Set up Gon
2121
run: brew tap conductorone/gon && brew install conductorone/gon/gon
2222
- name: Import Keychain Certs
@@ -43,7 +43,7 @@ jobs:
4343
- name: Set up Go
4444
uses: actions/setup-go@v4
4545
with:
46-
go-version: 1.22.x
46+
go-version: 1.23.x
4747
- name: Docker Login
4848
uses: docker/login-action@v1
4949
with:

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,24 @@ Check out [Baton](https://github.com/conductorone/baton) to learn more about the
1313
3. Installed 1Password [CLI Tool](https://developer.1password.com/docs/cli) on your local machine. For first time install please refer to the [Install](https://developer.1password.com/docs/cli/get-started/#install) chapter. It is not neccessary to do any other steps as the `baton-1password` will take care of creating an account and signing in.
1414
If you already have the CLI tool installed but need to upgrade it to the latest version please refer to [this](https://developer.1password.com/docs/cli/upgrade/) article.
1515

16+
IMPORTANT NOTE: If a service account is used, its token must be stored in a local environment variable (OP_SERVICE_ACCOUNT_TOKEN) in order for the 1Password CLI to authenticate properly:
17+
```
18+
OP_SERVICE_ACCOUNT_TOKEN=your-service-account-token
19+
```
20+
21+
## Connector capabilities
22+
23+
- The connector can be authenticated using either a regular user account or a 1Password service account.
24+
25+
- Sync Users, projects, groups and vaults.
26+
27+
- Supports Groups provision
28+
29+
- Support Vaults provision
30+
IMPORTANT NOTE: Vault provisioning is limited with a service account:
31+
When using a service account to run the connector, vault provisioning is limited by 1Password. Specifically, only vaults that were created by the same service account can be modified.
32+
Vaults that were created by other users or service accounts cannot be granted or revoked permissions using a service account.
33+
1634
## brew
1735

1836
```

pkg/connector/group.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,18 +122,16 @@ func (g *groupResourceType) Grants(ctx context.Context, resource *v2.Resource, _
122122
}
123123

124124
func (o *groupResourceType) Grant(ctx context.Context, principal *v2.Resource, entitlement *v2.Entitlement) (annotations.Annotations, error) {
125-
l := ctxzap.Extract(ctx)
126-
127125
if principal.Id.ResourceType != resourceTypeUser.Id {
128-
l.Warn(
129-
"baton-1password: only users can be granted group membership",
130-
zap.String("principal_type", principal.Id.ResourceType),
131-
zap.String("principal_id", principal.Id.Resource),
132-
)
133126
return nil, fmt.Errorf("baton-1password: only users can be granted group membership")
134127
}
135128

136-
err := o.cli.AddUserToGroup(ctx, entitlement.Resource.Id.Resource, entitlement.Slug, principal.Id.Resource)
129+
role, err := extractRoleFromEntitlementID(entitlement.Id)
130+
if err != nil {
131+
return nil, fmt.Errorf("could not extract role: %w", err)
132+
}
133+
134+
err = o.cli.AddUserToGroup(ctx, entitlement.Resource.Id.Resource, role, principal.Id.Resource)
137135

138136
if err != nil {
139137
return nil, fmt.Errorf("baton-1password: failed adding user to group")

pkg/connector/helpers.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package connector
22

33
import (
44
"fmt"
5+
"strings"
56

67
v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2"
78
"github.com/conductorone/baton-sdk/pkg/annotations"
89
ent "github.com/conductorone/baton-sdk/pkg/types/entitlement"
10+
mapset "github.com/deckarep/golang-set/v2"
911
)
1012

1113
// Populate entitlement options for a 1Password resource.
@@ -23,3 +25,76 @@ func annotationsForUserResourceType() annotations.Annotations {
2325
annos.Update(&v2.SkipEntitlementsAndGrants{})
2426
return annos
2527
}
28+
29+
func extractRoleFromEntitlementID(entitlementID string) (string, error) {
30+
parts := strings.Split(entitlementID, ":")
31+
if len(parts) != 3 {
32+
return "", fmt.Errorf("invalid entitlement ID: %s", entitlementID)
33+
}
34+
role := parts[2]
35+
// Formatting to replace spaces with _
36+
role = strings.ReplaceAll(role, " ", "_")
37+
return role, nil
38+
}
39+
40+
func uniqueStrings(input []string) []string {
41+
set := mapset.NewSet[string]()
42+
for _, s := range input {
43+
set.Add(s)
44+
}
45+
return set.ToSlice()
46+
}
47+
48+
func getPermissionsForGrantRevoke(permissionGrant string, accountType string, isRevoke bool) []string {
49+
if isRevoke {
50+
return getRevokePermissions(permissionGrant, accountType)
51+
}
52+
return getGrantPermissions(permissionGrant, accountType)
53+
}
54+
55+
func getRevokePermissions(permissionGrant string, accountType string) []string {
56+
switch permissionGrant {
57+
case memberEntitlement:
58+
if accountType == businessAccountType {
59+
return uniqueStrings(append(
60+
expandPermissionsForRevoke("view_items"),
61+
"manage_vault",
62+
))
63+
}
64+
return uniqueStrings(append(
65+
expandPermissionsForRevoke("allow_viewing"),
66+
"allow_managing",
67+
))
68+
69+
case managerEntitlement:
70+
if accountType == businessAccountType {
71+
return []string{"manage_vault"}
72+
}
73+
return []string{"allow_managing"}
74+
75+
default:
76+
return expandPermissionsForRevoke(permissionGrant)
77+
}
78+
}
79+
80+
func getGrantPermissions(permissionGrant string, accountType string) []string {
81+
switch permissionGrant {
82+
case memberEntitlement:
83+
if accountType == businessAccountType {
84+
return resolveDeps("view_items", reverseDependencyMap, make(map[string]bool))
85+
}
86+
return expandPermissions("allow_editing")
87+
88+
case managerEntitlement:
89+
if accountType == businessAccountType {
90+
return uniqueStrings(append(
91+
expandPermissions("view_items"),
92+
"manage_vault",
93+
))
94+
}
95+
return expandPermissions("allow_managing")
96+
97+
default:
98+
return expandPermissions(permissionGrant)
99+
}
100+
}

0 commit comments

Comments
 (0)