Skip to content

Commit fcf6fa6

Browse files
committed
fix: version-specific implementation for creating robot accs
1 parent b97e13d commit fcf6fa6

2 files changed

Lines changed: 165 additions & 5 deletions

File tree

pkg/harbor/client_test.go

Lines changed: 137 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ limitations under the License.
1717
package harbor
1818

1919
import (
20+
"encoding/json"
2021
"fmt"
22+
"io/ioutil"
2123
"net/http"
2224
"net/http/httptest"
2325
"testing"
@@ -34,17 +36,18 @@ func TestInfo(t *testing.T) {
3436
if err == nil {
3537
t.Errorf("client should not be constructed without user/password")
3638
}
39+
// info
40+
response = `{"harbor_version":"1.9.3"}`
3741
c, err := New(srv.URL, "foo", "bar", false)
3842
if err != nil {
3943
t.Fail()
4044
}
41-
// info
42-
response = `{"harbor_version":"1.2.3"}`
45+
4346
info, err := c.SystemInfo()
4447
if err != nil {
4548
t.Fail()
4649
}
47-
if info.HarborVersion != "1.2.3" {
50+
if info.HarborVersion != "1.9.3" {
4851
t.Errorf("incorrect harbor version returned")
4952
}
5053
}
@@ -77,11 +80,101 @@ func TestProjects(t *testing.T) {
7780
}
7881
}
7982

80-
func TestRobots(t *testing.T) {
83+
func TestRobotsPre110(t *testing.T) {
84+
var srv *httptest.Server
85+
srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
86+
res.WriteHeader(201)
87+
if req.URL.Path == "/api/systeminfo" {
88+
res.Write([]byte(`{"harbor_version":"1.9.3"}`))
89+
} else {
90+
body, _ := ioutil.ReadAll(req.Body)
91+
var r CreateRobotRequest
92+
json.Unmarshal(body, &r)
93+
if len(r.Access) != 2 {
94+
t.Errorf("wrong number of permissions. expected 2, found %d. body: %#v", len(r.Access), r)
95+
}
96+
res.Write([]byte(`{"name":"foo","token":"bar"}`))
97+
}
98+
}))
99+
defer srv.Close()
100+
c, err := New(srv.URL, "foo", "bar", false)
101+
if err != nil {
102+
t.Fail()
103+
}
104+
robot, err := c.CreateRobotAccount("foo", false, Project{Name: "example"})
105+
fmt.Printf("vals: %#v %#v", robot, err)
106+
if err != nil {
107+
t.FailNow()
108+
}
109+
if robot.Name != "foo" {
110+
t.Fail()
111+
}
112+
if robot.Token != "bar" {
113+
t.Fail()
114+
}
115+
}
116+
117+
func TestRobotsPushPre110(t *testing.T) {
118+
var srv *httptest.Server
119+
srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
120+
res.WriteHeader(201)
121+
if req.URL.Path == "/api/systeminfo" {
122+
res.Write([]byte(`{"harbor_version":"1.9.0"}`))
123+
} else {
124+
body, _ := ioutil.ReadAll(req.Body)
125+
var r CreateRobotRequest
126+
json.Unmarshal(body, &r)
127+
if len(r.Access) != 4 {
128+
t.Errorf("wrong number of permissions. expected 2, found %d. body: %#v", len(r.Access), r)
129+
}
130+
if r.Access[0].Action != "pull" {
131+
t.Errorf("unexpected action: %#v", r.Access[0])
132+
}
133+
if r.Access[1].Action != "pull" {
134+
t.Errorf("unexpected action: %#v", r.Access[1])
135+
}
136+
if r.Access[2].Action != "push" {
137+
t.Errorf("unexpected action: %#v", r.Access[2])
138+
}
139+
if r.Access[3].Action != "push" {
140+
t.Errorf("unexpected action: %#v", r.Access[3])
141+
}
142+
res.Write([]byte(`{"name":"foo","token":"bar"}`))
143+
}
144+
}))
145+
defer srv.Close()
146+
c, err := New(srv.URL, "foo", "bar", false)
147+
if err != nil {
148+
t.Fail()
149+
}
150+
robot, err := c.CreateRobotAccount("foo", true, Project{Name: "example"})
151+
fmt.Printf("vals: %#v %#v", robot, err)
152+
if err != nil {
153+
t.FailNow()
154+
}
155+
if robot.Name != "foo" {
156+
t.Fail()
157+
}
158+
if robot.Token != "bar" {
159+
t.Fail()
160+
}
161+
}
162+
163+
func TestRobotsPost110(t *testing.T) {
81164
var srv *httptest.Server
82165
srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
83166
res.WriteHeader(201)
84-
res.Write([]byte(`{"name":"foo","token":"bar"}`))
167+
if req.URL.Path == "/api/systeminfo" {
168+
res.Write([]byte(`{"harbor_version":"1.10.0"}`))
169+
} else {
170+
body, _ := ioutil.ReadAll(req.Body)
171+
var r CreateRobotRequest
172+
json.Unmarshal(body, &r)
173+
if len(r.Access) != 1 {
174+
t.Errorf("wrong number of permissions. expected 2, found %d body: %#v", len(r.Access), r)
175+
}
176+
res.Write([]byte(`{"name":"foo","token":"bar"}`))
177+
}
85178
}))
86179
defer srv.Close()
87180
c, err := New(srv.URL, "foo", "bar", false)
@@ -100,3 +193,42 @@ func TestRobots(t *testing.T) {
100193
t.Fail()
101194
}
102195
}
196+
func TestRobotsPushPost110(t *testing.T) {
197+
var srv *httptest.Server
198+
srv = httptest.NewServer(http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
199+
res.WriteHeader(201)
200+
if req.URL.Path == "/api/systeminfo" {
201+
res.Write([]byte(`{"harbor_version":"1.10.0"}`))
202+
} else {
203+
body, _ := ioutil.ReadAll(req.Body)
204+
var r CreateRobotRequest
205+
json.Unmarshal(body, &r)
206+
if len(r.Access) != 2 {
207+
t.Errorf("wrong number of permissions. expected 2, found %d. body: %#v", len(r.Access), r)
208+
}
209+
if r.Access[0].Action != "pull" {
210+
t.Errorf("unexpected action: %#v", r.Access[0])
211+
}
212+
if r.Access[1].Action != "push" {
213+
t.Errorf("unexpected action: %#v", r.Access[1])
214+
}
215+
res.Write([]byte(`{"name":"foo","token":"bar"}`))
216+
}
217+
}))
218+
defer srv.Close()
219+
c, err := New(srv.URL, "foo", "bar", false)
220+
if err != nil {
221+
t.Fail()
222+
}
223+
robot, err := c.CreateRobotAccount("foo", true, Project{Name: "example"})
224+
fmt.Printf("vals: %#v %#v", robot, err)
225+
if err != nil {
226+
t.FailNow()
227+
}
228+
if robot.Name != "foo" {
229+
t.Fail()
230+
}
231+
if robot.Token != "bar" {
232+
t.Fail()
233+
}
234+
}

pkg/harbor/robot.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ import (
2121
"encoding/json"
2222
"fmt"
2323
"io/ioutil"
24+
"strings"
25+
26+
"github.com/blang/semver"
2427
)
2528

2629
// Robot is the API response from Harbor
@@ -80,6 +83,18 @@ func (c *Client) GetRobotAccounts(project Project) ([]Robot, error) {
8083

8184
// CreateRobotAccount creates a robot account and return the name and token
8285
func (c *Client) CreateRobotAccount(name string, pushAccess bool, project Project) (*CreateRobotResponse, error) {
86+
// we have to check the api version before we make an API call
87+
// there is a quirk with the harbor API w/ permissions
88+
info, err := c.SystemInfo()
89+
if err != nil {
90+
return nil, fmt.Errorf("error calling system info: %s", err)
91+
}
92+
v, err := semver.Make(strings.TrimLeft(info.HarborVersion, "v"))
93+
if err != nil {
94+
return nil, fmt.Errorf("unable to parse harbor version")
95+
}
96+
v.Pre = nil
97+
v110 := semver.MustParse("1.10.0")
8398
var robotResponse CreateRobotResponse
8499
permissions := []CreateRobotRequestAccess{
85100
{
@@ -88,11 +103,24 @@ func (c *Client) CreateRobotAccount(name string, pushAccess bool, project Projec
88103
},
89104
}
90105

106+
if v.LT(v110) {
107+
permissions = append(permissions, CreateRobotRequestAccess{
108+
Resource: fmt.Sprintf("/project/%s/repository", project.Name),
109+
Action: "pull",
110+
})
111+
}
112+
91113
if pushAccess {
92114
permissions = append(permissions, CreateRobotRequestAccess{
93115
Resource: fmt.Sprintf("/project/%d/repository", project.ID),
94116
Action: "push",
95117
})
118+
if v.LT(v110) {
119+
permissions = append(permissions, CreateRobotRequestAccess{
120+
Resource: fmt.Sprintf("/project/%s/repository", project.Name),
121+
Action: "push",
122+
})
123+
}
96124
}
97125

98126
reqBody, err := json.Marshal(CreateRobotRequest{

0 commit comments

Comments
 (0)