+27
-22
appview/pages/templates/repo/settings/pipelines.html
+27
-22
appview/pages/templates/repo/settings/pipelines.html
···
20
20
<div class="col-span-1 md:col-span-2">
21
21
<h2 class="text-sm pb-2 uppercase font-bold">Spindle</h2>
22
22
<p class="text-gray-500 dark:text-gray-400">
23
-
Choose a spindle to execute your workflows on. Spindles can be
24
-
selfhosted,
23
+
Choose a spindle to execute your workflows on. Only repository owners
24
+
can configure spindles. Spindles can be selfhosted,
25
25
<a class="text-gray-500 dark:text-gray-400 underline" href="https://tangled.sh/@tangled.sh/core/blob/master/docs/spindle/hosting.md">
26
26
click to learn more.
27
27
</a>
28
28
</p>
29
29
</div>
30
-
<form hx-post="/{{ $.RepoInfo.FullName }}/settings/spindle" class="col-span-1 md:col-span-1 md:justify-self-end group flex gap-2 items-stretch">
31
-
<select
32
-
id="spindle"
33
-
name="spindle"
34
-
required
35
-
class="p-1 max-w-64 border border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"
36
-
{{ if not $.RepoInfo.Roles.IsOwner }}disabled{{ end }}>
37
-
<option value="" disabled selected >
38
-
Choose a spindle
39
-
</option>
40
-
{{ range $.Spindles }}
41
-
<option value="{{ . }}" class="py-1" {{ if eq . $.CurrentSpindle }}selected{{ end }}>
42
-
{{ . }}
30
+
{{ if not $.RepoInfo.Roles.IsOwner }}
31
+
<div class="col-span-1 md:col-span-1 md:justify-self-end group flex gap-2 items-stretch">
32
+
{{ or $.CurrentSpindle "No spindle configured" }}
33
+
</div>
34
+
{{ else }}
35
+
<form hx-post="/{{ $.RepoInfo.FullName }}/settings/spindle" class="col-span-1 md:col-span-1 md:justify-self-end group flex gap-2 items-stretch">
36
+
<select
37
+
id="spindle"
38
+
name="spindle"
39
+
required
40
+
class="p-1 max-w-64 border border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700">
41
+
<option value="" disabled>
42
+
Choose a spindle
43
43
</option>
44
-
{{ end }}
45
-
</select>
46
-
<button class="btn flex gap-2 items-center" type="submit" {{ if not $.RepoInfo.Roles.IsOwner }}disabled{{ end }}>
47
-
{{ i "check" "size-4" }}
48
-
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
49
-
</button>
50
-
</form>
44
+
{{ range $.Spindles }}
45
+
<option value="{{ . }}" class="py-1" {{ if eq . $.CurrentSpindle }}selected{{ end }}>
46
+
{{ . }}
47
+
</option>
48
+
{{ end }}
49
+
</select>
50
+
<button class="btn flex gap-2 items-center" type="submit" {{ if not $.RepoInfo.Roles.IsOwner }}disabled{{ end }}>
51
+
{{ i "check" "size-4" }}
52
+
{{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
53
+
</button>
54
+
</form>
55
+
{{ end }}
51
56
</div>
52
57
{{ end }}
53
58
+2
-2
appview/repo/repo.go
+2
-2
appview/repo/repo.go
···
1225
1225
f, err := rp.repoResolver.Resolve(r)
1226
1226
user := rp.oauth.GetUser(r)
1227
1227
1228
-
// all spindles that this user is a member of
1229
-
spindles, err := rp.enforcer.GetSpindlesForUser(user.Did)
1228
+
// all spindles that the repo owner is a member of
1229
+
spindles, err := rp.enforcer.GetSpindlesForUser(f.OwnerDid())
1230
1230
if err != nil {
1231
1231
log.Println("failed to fetch spindles", err)
1232
1232
return
-1
knotserver/ingester.go
-1
knotserver/ingester.go
+19
-3
spindle/ingester.go
+19
-3
spindle/ingester.go
···
3
3
import (
4
4
"context"
5
5
"encoding/json"
6
+
"errors"
6
7
"fmt"
7
-
"path/filepath"
8
8
9
9
"tangled.sh/tangled.sh/core/api/tangled"
10
10
"tangled.sh/tangled.sh/core/eventconsumer"
···
100
100
return nil
101
101
}
102
102
103
-
func (s *Spindle) ingestRepo(_ context.Context, e *models.Event) error {
103
+
func (s *Spindle) ingestRepo(ctx context.Context, e *models.Event) error {
104
104
var err error
105
+
did := e.Did
106
+
resolver := idresolver.DefaultResolver()
105
107
106
108
l := s.l.With("component", "ingester", "record", tangled.RepoNSID)
107
109
···
137
139
return fmt.Errorf("failed to add repo: %w", err)
138
140
}
139
141
142
+
didSlashRepo, err := securejoin.SecureJoin(record.Owner, record.Name)
143
+
if err != nil {
144
+
return err
145
+
}
146
+
140
147
// add repo to rbac
141
-
if err := s.e.AddRepo(record.Owner, rbac.ThisServer, filepath.Join(record.Owner, record.Name)); err != nil {
148
+
if err := s.e.AddRepo(record.Owner, rbac.ThisServer, didSlashRepo); err != nil {
142
149
l.Error("failed to add repo to enforcer", "error", err)
143
150
return fmt.Errorf("failed to add repo: %w", err)
151
+
}
152
+
153
+
// add collaborators to rbac
154
+
owner, err := resolver.ResolveIdent(ctx, did)
155
+
if err != nil || owner.Handle.IsInvalidHandle() {
156
+
return err
157
+
}
158
+
if err := s.fetchAndAddCollaborators(ctx, owner, didSlashRepo); err != nil {
159
+
return err
144
160
}
145
161
146
162
// add this knot to the event consumer