registry_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. package registry // import "github.com/docker/docker/registry"
  2. import (
  3. "net/http"
  4. "net/http/httputil"
  5. "os"
  6. "strings"
  7. "testing"
  8. "github.com/docker/distribution/reference"
  9. "github.com/docker/distribution/registry/client/transport"
  10. "github.com/docker/docker/api/types/registry"
  11. "gotest.tools/v3/assert"
  12. is "gotest.tools/v3/assert/cmp"
  13. "gotest.tools/v3/skip"
  14. )
  15. func spawnTestRegistrySession(t *testing.T) *session {
  16. authConfig := &registry.AuthConfig{}
  17. endpoint, err := newV1Endpoint(makeIndex("/v1/"), nil)
  18. if err != nil {
  19. t.Fatal(err)
  20. }
  21. userAgent := "docker test client"
  22. var tr http.RoundTripper = debugTransport{newTransport(nil), t.Log}
  23. tr = transport.NewTransport(newAuthTransport(tr, authConfig, false), Headers(userAgent, nil)...)
  24. client := httpClient(tr)
  25. if err := authorizeClient(client, authConfig, endpoint); err != nil {
  26. t.Fatal(err)
  27. }
  28. r := newSession(client, endpoint)
  29. // In a normal scenario for the v1 registry, the client should send a `X-Docker-Token: true`
  30. // header while authenticating, in order to retrieve a token that can be later used to
  31. // perform authenticated actions.
  32. //
  33. // The mock v1 registry does not support that, (TODO(tiborvass): support it), instead,
  34. // it will consider authenticated any request with the header `X-Docker-Token: fake-token`.
  35. //
  36. // Because we know that the client's transport is an `*authTransport` we simply cast it,
  37. // in order to set the internal cached token to the fake token, and thus send that fake token
  38. // upon every subsequent requests.
  39. r.client.Transport.(*authTransport).token = []string{"fake-token"}
  40. return r
  41. }
  42. func TestPingRegistryEndpoint(t *testing.T) {
  43. skip.If(t, os.Getuid() != 0, "skipping test that requires root")
  44. testPing := func(index *registry.IndexInfo, expectedStandalone bool, assertMessage string) {
  45. ep, err := newV1Endpoint(index, nil)
  46. if err != nil {
  47. t.Fatal(err)
  48. }
  49. regInfo, err := ep.ping()
  50. if err != nil {
  51. t.Fatal(err)
  52. }
  53. assert.Equal(t, regInfo.Standalone, expectedStandalone, assertMessage)
  54. }
  55. testPing(makeIndex("/v1/"), true, "Expected standalone to be true (default)")
  56. testPing(makeHTTPSIndex("/v1/"), true, "Expected standalone to be true (default)")
  57. testPing(makePublicIndex(), false, "Expected standalone to be false for public index")
  58. }
  59. func TestEndpoint(t *testing.T) {
  60. skip.If(t, os.Getuid() != 0, "skipping test that requires root")
  61. // Simple wrapper to fail test if err != nil
  62. expandEndpoint := func(index *registry.IndexInfo) *v1Endpoint {
  63. endpoint, err := newV1Endpoint(index, nil)
  64. if err != nil {
  65. t.Fatal(err)
  66. }
  67. return endpoint
  68. }
  69. assertInsecureIndex := func(index *registry.IndexInfo) {
  70. index.Secure = true
  71. _, err := newV1Endpoint(index, nil)
  72. assert.ErrorContains(t, err, "insecure-registry", index.Name+": Expected insecure-registry error for insecure index")
  73. index.Secure = false
  74. }
  75. assertSecureIndex := func(index *registry.IndexInfo) {
  76. index.Secure = true
  77. _, err := newV1Endpoint(index, nil)
  78. assert.ErrorContains(t, err, "certificate signed by unknown authority", index.Name+": Expected cert error for secure index")
  79. index.Secure = false
  80. }
  81. index := &registry.IndexInfo{}
  82. index.Name = makeURL("/v1/")
  83. endpoint := expandEndpoint(index)
  84. assert.Equal(t, endpoint.String(), index.Name, "Expected endpoint to be "+index.Name)
  85. assertInsecureIndex(index)
  86. index.Name = makeURL("")
  87. endpoint = expandEndpoint(index)
  88. assert.Equal(t, endpoint.String(), index.Name+"/v1/", index.Name+": Expected endpoint to be "+index.Name+"/v1/")
  89. assertInsecureIndex(index)
  90. httpURL := makeURL("")
  91. index.Name = strings.SplitN(httpURL, "://", 2)[1]
  92. endpoint = expandEndpoint(index)
  93. assert.Equal(t, endpoint.String(), httpURL+"/v1/", index.Name+": Expected endpoint to be "+httpURL+"/v1/")
  94. assertInsecureIndex(index)
  95. index.Name = makeHTTPSURL("/v1/")
  96. endpoint = expandEndpoint(index)
  97. assert.Equal(t, endpoint.String(), index.Name, "Expected endpoint to be "+index.Name)
  98. assertSecureIndex(index)
  99. index.Name = makeHTTPSURL("")
  100. endpoint = expandEndpoint(index)
  101. assert.Equal(t, endpoint.String(), index.Name+"/v1/", index.Name+": Expected endpoint to be "+index.Name+"/v1/")
  102. assertSecureIndex(index)
  103. httpsURL := makeHTTPSURL("")
  104. index.Name = strings.SplitN(httpsURL, "://", 2)[1]
  105. endpoint = expandEndpoint(index)
  106. assert.Equal(t, endpoint.String(), httpsURL+"/v1/", index.Name+": Expected endpoint to be "+httpsURL+"/v1/")
  107. assertSecureIndex(index)
  108. badEndpoints := []string{
  109. "http://127.0.0.1/v1/",
  110. "https://127.0.0.1/v1/",
  111. "http://127.0.0.1",
  112. "https://127.0.0.1",
  113. "127.0.0.1",
  114. }
  115. for _, address := range badEndpoints {
  116. index.Name = address
  117. _, err := newV1Endpoint(index, nil)
  118. assert.Check(t, err != nil, "Expected error while expanding bad endpoint: %s", address)
  119. }
  120. }
  121. func TestParseRepositoryInfo(t *testing.T) {
  122. type staticRepositoryInfo struct {
  123. Index *registry.IndexInfo
  124. RemoteName string
  125. CanonicalName string
  126. LocalName string
  127. Official bool
  128. }
  129. expectedRepoInfos := map[string]staticRepositoryInfo{
  130. "fooo/bar": {
  131. Index: &registry.IndexInfo{
  132. Name: IndexName,
  133. Official: true,
  134. },
  135. RemoteName: "fooo/bar",
  136. LocalName: "fooo/bar",
  137. CanonicalName: "docker.io/fooo/bar",
  138. Official: false,
  139. },
  140. "library/ubuntu": {
  141. Index: &registry.IndexInfo{
  142. Name: IndexName,
  143. Official: true,
  144. },
  145. RemoteName: "library/ubuntu",
  146. LocalName: "ubuntu",
  147. CanonicalName: "docker.io/library/ubuntu",
  148. Official: true,
  149. },
  150. "nonlibrary/ubuntu": {
  151. Index: &registry.IndexInfo{
  152. Name: IndexName,
  153. Official: true,
  154. },
  155. RemoteName: "nonlibrary/ubuntu",
  156. LocalName: "nonlibrary/ubuntu",
  157. CanonicalName: "docker.io/nonlibrary/ubuntu",
  158. Official: false,
  159. },
  160. "ubuntu": {
  161. Index: &registry.IndexInfo{
  162. Name: IndexName,
  163. Official: true,
  164. },
  165. RemoteName: "library/ubuntu",
  166. LocalName: "ubuntu",
  167. CanonicalName: "docker.io/library/ubuntu",
  168. Official: true,
  169. },
  170. "other/library": {
  171. Index: &registry.IndexInfo{
  172. Name: IndexName,
  173. Official: true,
  174. },
  175. RemoteName: "other/library",
  176. LocalName: "other/library",
  177. CanonicalName: "docker.io/other/library",
  178. Official: false,
  179. },
  180. "127.0.0.1:8000/private/moonbase": {
  181. Index: &registry.IndexInfo{
  182. Name: "127.0.0.1:8000",
  183. Official: false,
  184. },
  185. RemoteName: "private/moonbase",
  186. LocalName: "127.0.0.1:8000/private/moonbase",
  187. CanonicalName: "127.0.0.1:8000/private/moonbase",
  188. Official: false,
  189. },
  190. "127.0.0.1:8000/privatebase": {
  191. Index: &registry.IndexInfo{
  192. Name: "127.0.0.1:8000",
  193. Official: false,
  194. },
  195. RemoteName: "privatebase",
  196. LocalName: "127.0.0.1:8000/privatebase",
  197. CanonicalName: "127.0.0.1:8000/privatebase",
  198. Official: false,
  199. },
  200. "localhost:8000/private/moonbase": {
  201. Index: &registry.IndexInfo{
  202. Name: "localhost:8000",
  203. Official: false,
  204. },
  205. RemoteName: "private/moonbase",
  206. LocalName: "localhost:8000/private/moonbase",
  207. CanonicalName: "localhost:8000/private/moonbase",
  208. Official: false,
  209. },
  210. "localhost:8000/privatebase": {
  211. Index: &registry.IndexInfo{
  212. Name: "localhost:8000",
  213. Official: false,
  214. },
  215. RemoteName: "privatebase",
  216. LocalName: "localhost:8000/privatebase",
  217. CanonicalName: "localhost:8000/privatebase",
  218. Official: false,
  219. },
  220. "example.com/private/moonbase": {
  221. Index: &registry.IndexInfo{
  222. Name: "example.com",
  223. Official: false,
  224. },
  225. RemoteName: "private/moonbase",
  226. LocalName: "example.com/private/moonbase",
  227. CanonicalName: "example.com/private/moonbase",
  228. Official: false,
  229. },
  230. "example.com/privatebase": {
  231. Index: &registry.IndexInfo{
  232. Name: "example.com",
  233. Official: false,
  234. },
  235. RemoteName: "privatebase",
  236. LocalName: "example.com/privatebase",
  237. CanonicalName: "example.com/privatebase",
  238. Official: false,
  239. },
  240. "example.com:8000/private/moonbase": {
  241. Index: &registry.IndexInfo{
  242. Name: "example.com:8000",
  243. Official: false,
  244. },
  245. RemoteName: "private/moonbase",
  246. LocalName: "example.com:8000/private/moonbase",
  247. CanonicalName: "example.com:8000/private/moonbase",
  248. Official: false,
  249. },
  250. "example.com:8000/privatebase": {
  251. Index: &registry.IndexInfo{
  252. Name: "example.com:8000",
  253. Official: false,
  254. },
  255. RemoteName: "privatebase",
  256. LocalName: "example.com:8000/privatebase",
  257. CanonicalName: "example.com:8000/privatebase",
  258. Official: false,
  259. },
  260. "localhost/private/moonbase": {
  261. Index: &registry.IndexInfo{
  262. Name: "localhost",
  263. Official: false,
  264. },
  265. RemoteName: "private/moonbase",
  266. LocalName: "localhost/private/moonbase",
  267. CanonicalName: "localhost/private/moonbase",
  268. Official: false,
  269. },
  270. "localhost/privatebase": {
  271. Index: &registry.IndexInfo{
  272. Name: "localhost",
  273. Official: false,
  274. },
  275. RemoteName: "privatebase",
  276. LocalName: "localhost/privatebase",
  277. CanonicalName: "localhost/privatebase",
  278. Official: false,
  279. },
  280. IndexName + "/public/moonbase": {
  281. Index: &registry.IndexInfo{
  282. Name: IndexName,
  283. Official: true,
  284. },
  285. RemoteName: "public/moonbase",
  286. LocalName: "public/moonbase",
  287. CanonicalName: "docker.io/public/moonbase",
  288. Official: false,
  289. },
  290. "index." + IndexName + "/public/moonbase": {
  291. Index: &registry.IndexInfo{
  292. Name: IndexName,
  293. Official: true,
  294. },
  295. RemoteName: "public/moonbase",
  296. LocalName: "public/moonbase",
  297. CanonicalName: "docker.io/public/moonbase",
  298. Official: false,
  299. },
  300. "ubuntu-12.04-base": {
  301. Index: &registry.IndexInfo{
  302. Name: IndexName,
  303. Official: true,
  304. },
  305. RemoteName: "library/ubuntu-12.04-base",
  306. LocalName: "ubuntu-12.04-base",
  307. CanonicalName: "docker.io/library/ubuntu-12.04-base",
  308. Official: true,
  309. },
  310. IndexName + "/ubuntu-12.04-base": {
  311. Index: &registry.IndexInfo{
  312. Name: IndexName,
  313. Official: true,
  314. },
  315. RemoteName: "library/ubuntu-12.04-base",
  316. LocalName: "ubuntu-12.04-base",
  317. CanonicalName: "docker.io/library/ubuntu-12.04-base",
  318. Official: true,
  319. },
  320. "index." + IndexName + "/ubuntu-12.04-base": {
  321. Index: &registry.IndexInfo{
  322. Name: IndexName,
  323. Official: true,
  324. },
  325. RemoteName: "library/ubuntu-12.04-base",
  326. LocalName: "ubuntu-12.04-base",
  327. CanonicalName: "docker.io/library/ubuntu-12.04-base",
  328. Official: true,
  329. },
  330. }
  331. for reposName, expectedRepoInfo := range expectedRepoInfos {
  332. named, err := reference.ParseNormalizedNamed(reposName)
  333. if err != nil {
  334. t.Error(err)
  335. }
  336. repoInfo, err := ParseRepositoryInfo(named)
  337. if err != nil {
  338. t.Error(err)
  339. } else {
  340. assert.Check(t, is.Equal(repoInfo.Index.Name, expectedRepoInfo.Index.Name), reposName)
  341. assert.Check(t, is.Equal(reference.Path(repoInfo.Name), expectedRepoInfo.RemoteName), reposName)
  342. assert.Check(t, is.Equal(reference.FamiliarName(repoInfo.Name), expectedRepoInfo.LocalName), reposName)
  343. assert.Check(t, is.Equal(repoInfo.Name.Name(), expectedRepoInfo.CanonicalName), reposName)
  344. assert.Check(t, is.Equal(repoInfo.Index.Official, expectedRepoInfo.Index.Official), reposName)
  345. assert.Check(t, is.Equal(repoInfo.Official, expectedRepoInfo.Official), reposName)
  346. }
  347. }
  348. }
  349. func TestNewIndexInfo(t *testing.T) {
  350. testIndexInfo := func(config *serviceConfig, expectedIndexInfos map[string]*registry.IndexInfo) {
  351. for indexName, expectedIndexInfo := range expectedIndexInfos {
  352. index, err := newIndexInfo(config, indexName)
  353. if err != nil {
  354. t.Fatal(err)
  355. } else {
  356. assert.Check(t, is.Equal(index.Name, expectedIndexInfo.Name), indexName+" name")
  357. assert.Check(t, is.Equal(index.Official, expectedIndexInfo.Official), indexName+" is official")
  358. assert.Check(t, is.Equal(index.Secure, expectedIndexInfo.Secure), indexName+" is secure")
  359. assert.Check(t, is.Equal(len(index.Mirrors), len(expectedIndexInfo.Mirrors)), indexName+" mirrors")
  360. }
  361. }
  362. }
  363. config := emptyServiceConfig
  364. var noMirrors []string
  365. expectedIndexInfos := map[string]*registry.IndexInfo{
  366. IndexName: {
  367. Name: IndexName,
  368. Official: true,
  369. Secure: true,
  370. Mirrors: noMirrors,
  371. },
  372. "index." + IndexName: {
  373. Name: IndexName,
  374. Official: true,
  375. Secure: true,
  376. Mirrors: noMirrors,
  377. },
  378. "example.com": {
  379. Name: "example.com",
  380. Official: false,
  381. Secure: true,
  382. Mirrors: noMirrors,
  383. },
  384. "127.0.0.1:5000": {
  385. Name: "127.0.0.1:5000",
  386. Official: false,
  387. Secure: false,
  388. Mirrors: noMirrors,
  389. },
  390. }
  391. testIndexInfo(config, expectedIndexInfos)
  392. publicMirrors := []string{"http://mirror1.local", "http://mirror2.local"}
  393. var err error
  394. config, err = makeServiceConfig(publicMirrors, []string{"example.com"})
  395. if err != nil {
  396. t.Fatal(err)
  397. }
  398. expectedIndexInfos = map[string]*registry.IndexInfo{
  399. IndexName: {
  400. Name: IndexName,
  401. Official: true,
  402. Secure: true,
  403. Mirrors: publicMirrors,
  404. },
  405. "index." + IndexName: {
  406. Name: IndexName,
  407. Official: true,
  408. Secure: true,
  409. Mirrors: publicMirrors,
  410. },
  411. "example.com": {
  412. Name: "example.com",
  413. Official: false,
  414. Secure: false,
  415. Mirrors: noMirrors,
  416. },
  417. "example.com:5000": {
  418. Name: "example.com:5000",
  419. Official: false,
  420. Secure: true,
  421. Mirrors: noMirrors,
  422. },
  423. "127.0.0.1": {
  424. Name: "127.0.0.1",
  425. Official: false,
  426. Secure: false,
  427. Mirrors: noMirrors,
  428. },
  429. "127.0.0.1:5000": {
  430. Name: "127.0.0.1:5000",
  431. Official: false,
  432. Secure: false,
  433. Mirrors: noMirrors,
  434. },
  435. "other.com": {
  436. Name: "other.com",
  437. Official: false,
  438. Secure: true,
  439. Mirrors: noMirrors,
  440. },
  441. }
  442. testIndexInfo(config, expectedIndexInfos)
  443. config, err = makeServiceConfig(nil, []string{"42.42.0.0/16"})
  444. if err != nil {
  445. t.Fatal(err)
  446. }
  447. expectedIndexInfos = map[string]*registry.IndexInfo{
  448. "example.com": {
  449. Name: "example.com",
  450. Official: false,
  451. Secure: false,
  452. Mirrors: noMirrors,
  453. },
  454. "example.com:5000": {
  455. Name: "example.com:5000",
  456. Official: false,
  457. Secure: false,
  458. Mirrors: noMirrors,
  459. },
  460. "127.0.0.1": {
  461. Name: "127.0.0.1",
  462. Official: false,
  463. Secure: false,
  464. Mirrors: noMirrors,
  465. },
  466. "127.0.0.1:5000": {
  467. Name: "127.0.0.1:5000",
  468. Official: false,
  469. Secure: false,
  470. Mirrors: noMirrors,
  471. },
  472. "other.com": {
  473. Name: "other.com",
  474. Official: false,
  475. Secure: true,
  476. Mirrors: noMirrors,
  477. },
  478. }
  479. testIndexInfo(config, expectedIndexInfos)
  480. }
  481. func TestMirrorEndpointLookup(t *testing.T) {
  482. skip.If(t, os.Getuid() != 0, "skipping test that requires root")
  483. containsMirror := func(endpoints []APIEndpoint) bool {
  484. for _, pe := range endpoints {
  485. if pe.URL.Host == "my.mirror" {
  486. return true
  487. }
  488. }
  489. return false
  490. }
  491. cfg, err := makeServiceConfig([]string{"https://my.mirror"}, nil)
  492. if err != nil {
  493. t.Fatal(err)
  494. }
  495. s := Service{config: cfg}
  496. imageName, err := reference.WithName(IndexName + "/test/image")
  497. if err != nil {
  498. t.Error(err)
  499. }
  500. pushAPIEndpoints, err := s.LookupPushEndpoints(reference.Domain(imageName))
  501. if err != nil {
  502. t.Fatal(err)
  503. }
  504. if containsMirror(pushAPIEndpoints) {
  505. t.Fatal("Push endpoint should not contain mirror")
  506. }
  507. pullAPIEndpoints, err := s.LookupPullEndpoints(reference.Domain(imageName))
  508. if err != nil {
  509. t.Fatal(err)
  510. }
  511. if !containsMirror(pullAPIEndpoints) {
  512. t.Fatal("Pull endpoint should contain mirror")
  513. }
  514. }
  515. func TestSearchRepositories(t *testing.T) {
  516. r := spawnTestRegistrySession(t)
  517. results, err := r.searchRepositories("fakequery", 25)
  518. if err != nil {
  519. t.Fatal(err)
  520. }
  521. if results == nil {
  522. t.Fatal("Expected non-nil SearchResults object")
  523. }
  524. assert.Equal(t, results.NumResults, 1, "Expected 1 search results")
  525. assert.Equal(t, results.Query, "fakequery", "Expected 'fakequery' as query")
  526. assert.Equal(t, results.Results[0].StarCount, 42, "Expected 'fakeimage' to have 42 stars")
  527. }
  528. func TestTrustedLocation(t *testing.T) {
  529. for _, url := range []string{"http://example.com", "https://example.com:7777", "http://docker.io", "http://test.docker.com", "https://fakedocker.com"} {
  530. req, _ := http.NewRequest(http.MethodGet, url, nil)
  531. assert.Check(t, !trustedLocation(req))
  532. }
  533. for _, url := range []string{"https://docker.io", "https://test.docker.com:80"} {
  534. req, _ := http.NewRequest(http.MethodGet, url, nil)
  535. assert.Check(t, trustedLocation(req))
  536. }
  537. }
  538. func TestAddRequiredHeadersToRedirectedRequests(t *testing.T) {
  539. for _, urls := range [][]string{
  540. {"http://docker.io", "https://docker.com"},
  541. {"https://foo.docker.io:7777", "http://bar.docker.com"},
  542. {"https://foo.docker.io", "https://example.com"},
  543. } {
  544. reqFrom, _ := http.NewRequest(http.MethodGet, urls[0], nil)
  545. reqFrom.Header.Add("Content-Type", "application/json")
  546. reqFrom.Header.Add("Authorization", "super_secret")
  547. reqTo, _ := http.NewRequest(http.MethodGet, urls[1], nil)
  548. _ = addRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom})
  549. if len(reqTo.Header) != 1 {
  550. t.Fatalf("Expected 1 headers, got %d", len(reqTo.Header))
  551. }
  552. if reqTo.Header.Get("Content-Type") != "application/json" {
  553. t.Fatal("'Content-Type' should be 'application/json'")
  554. }
  555. if reqTo.Header.Get("Authorization") != "" {
  556. t.Fatal("'Authorization' should be empty")
  557. }
  558. }
  559. for _, urls := range [][]string{
  560. {"https://docker.io", "https://docker.com"},
  561. {"https://foo.docker.io:7777", "https://bar.docker.com"},
  562. } {
  563. reqFrom, _ := http.NewRequest(http.MethodGet, urls[0], nil)
  564. reqFrom.Header.Add("Content-Type", "application/json")
  565. reqFrom.Header.Add("Authorization", "super_secret")
  566. reqTo, _ := http.NewRequest(http.MethodGet, urls[1], nil)
  567. _ = addRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom})
  568. if len(reqTo.Header) != 2 {
  569. t.Fatalf("Expected 2 headers, got %d", len(reqTo.Header))
  570. }
  571. if reqTo.Header.Get("Content-Type") != "application/json" {
  572. t.Fatal("'Content-Type' should be 'application/json'")
  573. }
  574. if reqTo.Header.Get("Authorization") != "super_secret" {
  575. t.Fatal("'Authorization' should be 'super_secret'")
  576. }
  577. }
  578. }
  579. func TestAllowNondistributableArtifacts(t *testing.T) {
  580. tests := []struct {
  581. addr string
  582. registries []string
  583. expected bool
  584. }{
  585. {IndexName, nil, false},
  586. {"example.com", []string{}, false},
  587. {"example.com", []string{"example.com"}, true},
  588. {"localhost", []string{"localhost:5000"}, false},
  589. {"localhost:5000", []string{"localhost:5000"}, true},
  590. {"localhost", []string{"example.com"}, false},
  591. {"127.0.0.1:5000", []string{"127.0.0.1:5000"}, true},
  592. {"localhost", nil, false},
  593. {"localhost:5000", nil, false},
  594. {"127.0.0.1", nil, false},
  595. {"localhost", []string{"example.com"}, false},
  596. {"127.0.0.1", []string{"example.com"}, false},
  597. {"example.com", nil, false},
  598. {"example.com", []string{"example.com"}, true},
  599. {"127.0.0.1", []string{"example.com"}, false},
  600. {"127.0.0.1:5000", []string{"example.com"}, false},
  601. {"example.com:5000", []string{"42.42.0.0/16"}, true},
  602. {"example.com", []string{"42.42.0.0/16"}, true},
  603. {"example.com:5000", []string{"42.42.42.42/8"}, true},
  604. {"127.0.0.1:5000", []string{"127.0.0.0/8"}, true},
  605. {"42.42.42.42:5000", []string{"42.1.1.1/8"}, true},
  606. {"invalid.example.com", []string{"42.42.0.0/16"}, false},
  607. {"invalid.example.com", []string{"invalid.example.com"}, true},
  608. {"invalid.example.com:5000", []string{"invalid.example.com"}, false},
  609. {"invalid.example.com:5000", []string{"invalid.example.com:5000"}, true},
  610. }
  611. for _, tt := range tests {
  612. config, err := newServiceConfig(ServiceOptions{
  613. AllowNondistributableArtifacts: tt.registries,
  614. })
  615. if err != nil {
  616. t.Error(err)
  617. }
  618. if v := config.allowNondistributableArtifacts(tt.addr); v != tt.expected {
  619. t.Errorf("allowNondistributableArtifacts failed for %q %v, expected %v got %v", tt.addr, tt.registries, tt.expected, v)
  620. }
  621. }
  622. }
  623. func TestIsSecureIndex(t *testing.T) {
  624. tests := []struct {
  625. addr string
  626. insecureRegistries []string
  627. expected bool
  628. }{
  629. {IndexName, nil, true},
  630. {"example.com", []string{}, true},
  631. {"example.com", []string{"example.com"}, false},
  632. {"localhost", []string{"localhost:5000"}, false},
  633. {"localhost:5000", []string{"localhost:5000"}, false},
  634. {"localhost", []string{"example.com"}, false},
  635. {"127.0.0.1:5000", []string{"127.0.0.1:5000"}, false},
  636. {"localhost", nil, false},
  637. {"localhost:5000", nil, false},
  638. {"127.0.0.1", nil, false},
  639. {"localhost", []string{"example.com"}, false},
  640. {"127.0.0.1", []string{"example.com"}, false},
  641. {"example.com", nil, true},
  642. {"example.com", []string{"example.com"}, false},
  643. {"127.0.0.1", []string{"example.com"}, false},
  644. {"127.0.0.1:5000", []string{"example.com"}, false},
  645. {"example.com:5000", []string{"42.42.0.0/16"}, false},
  646. {"example.com", []string{"42.42.0.0/16"}, false},
  647. {"example.com:5000", []string{"42.42.42.42/8"}, false},
  648. {"127.0.0.1:5000", []string{"127.0.0.0/8"}, false},
  649. {"42.42.42.42:5000", []string{"42.1.1.1/8"}, false},
  650. {"invalid.example.com", []string{"42.42.0.0/16"}, true},
  651. {"invalid.example.com", []string{"invalid.example.com"}, false},
  652. {"invalid.example.com:5000", []string{"invalid.example.com"}, true},
  653. {"invalid.example.com:5000", []string{"invalid.example.com:5000"}, false},
  654. }
  655. for _, tt := range tests {
  656. config, err := makeServiceConfig(nil, tt.insecureRegistries)
  657. if err != nil {
  658. t.Error(err)
  659. }
  660. if sec := config.isSecureIndex(tt.addr); sec != tt.expected {
  661. t.Errorf("isSecureIndex failed for %q %v, expected %v got %v", tt.addr, tt.insecureRegistries, tt.expected, sec)
  662. }
  663. }
  664. }
  665. type debugTransport struct {
  666. http.RoundTripper
  667. log func(...interface{})
  668. }
  669. func (tr debugTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  670. dump, err := httputil.DumpRequestOut(req, false)
  671. if err != nil {
  672. tr.log("could not dump request")
  673. }
  674. tr.log(string(dump))
  675. resp, err := tr.RoundTripper.RoundTrip(req)
  676. if err != nil {
  677. return nil, err
  678. }
  679. dump, err = httputil.DumpResponse(resp, false)
  680. if err != nil {
  681. tr.log("could not dump response")
  682. }
  683. tr.log(string(dump))
  684. return resp, err
  685. }