Compare commits

...
5 Commits
Author SHA1 Message Date
Fedor KorotkovandNikolay Edigaryev 2f5a6790d8 Refactored registry token handling (#57)
* Refactored registry token handling

* Update Sources/tart/OCI/Registry.swift

Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com>

* Target our dedicated M1 Mini

Co-authored-by: Nikolay Edigaryev <edigaryev@gmail.com>
2022-05-09 16:13:22 +03:00
Fedor Korotkov cc697b4f6e More images in docs (#56)
* More images in docs

* More images in docs

* Updated GIF
2022-05-09 12:59:51 +03:00
Nikolay Edigaryev f6acbe8fe5 Registry: invalidate expired tokens (#55) 2022-05-08 19:46:11 -04:00
Fedor Korotkov 341fd168b3 Fixed release build entitlements (#54) 2022-05-08 13:05:10 +03:00
Fedor Korotkov e8a6efa60a Return title to docs (#53)
* Return title to docs

* smaller
2022-05-07 11:24:25 +03:00
8 changed files with 54 additions and 15 deletions
+1 -2
View File
@@ -1,7 +1,6 @@
persistent_worker:
labels:
os: darwin
arch: arm64
name: Mac-Mini-M1
task:
name: Test
+1
View File
@@ -1 +1,2 @@
*.png filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
-3
View File
@@ -12,9 +12,6 @@ builds:
before:
hooks:
- swift build -c release --product tart
after:
hooks:
- codesign --sign - --entitlements Resources/tart.entitlements --force .build/arm64-apple-macosx/release/tart
archives:
+10 -2
View File
@@ -1,4 +1,4 @@
![tart VM view app](Resources/TartScreenshot.png)
![Tart – open source virtualization for your automation needs](Resources/TartSocial.png)
*Tart* is a virtualization toolset to build, run and manage virtual machines on Apple Silicon.
Built by CI engineers for your automation needs. Here are some highlights of Tart:
@@ -16,6 +16,8 @@ tart clone ghcr.io/cirruslabs/macos-monterey-base:latest monterey-base
tart run monterey-base
```
![tart VM view app](Resources/TartScreenshot.png)
## CI Integration
[Cirrus CLI](https://github.com/cirruslabs/cirrus-cli) is an open-sourced CI-agnostic tool that can run workloads
@@ -28,7 +30,11 @@ task:
macos_instance:
# can be a remote or a local virtual machine
image: ghcr.io/cirruslabs/macos-monterey-base:latest
script: echo "Hello from within a Tart VM!"
hello_script:
- echo "Hello from within a Tart VM!"
- echo "Here is my CPU info:"
- sysctl -n machdep.cpu.brand_string
- sleep 15
```
Run it locally or in CI with the following command:
@@ -38,6 +44,8 @@ brew install cirruslabs/cli/cirrus
cirrus run
```
![Cirrus CLI Run](Resources/TartCirrusCLI.gif)
[Cirrus CI](https://cirrus-ci.org/) already leverages Tart to power its macOS cloud infrastructure. The `.cirrus.yml`
config from above will just work in Cirrus CI and your tasks will be executed inside Tart VMs in our cloud.
+3
View File
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:8a3a324193c4bd7797102765ab16f44adf58e49ca615bac3963cefd0d3a10594
size 339678
+2 -2
View File
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:46046004d63f9b4b7de3d5d3f9ca14367a9e4b0a124b4b0b65225f67a0d0fb45
size 1266887
oid sha256:3a43f541b1ab0b57ae2060d371cba5dbb1f5c80b89c76434b7154d8144f66e61
size 205325
+3
View File
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:769dcd5411f44071cb46f63459118fef728c866a581cf94a28811f407ca9827d
size 606936
+34 -6
View File
@@ -8,14 +8,37 @@ enum RegistryError: Error {
}
struct TokenResponse: Decodable {
let creationTime = Date()
var token: String
var expires_in: Int?
var tokenExpiresAt: Date {
get {
// Tokens can expire and expire_in field is used to determine when:
//
// >The duration in seconds since the token was issued that it will remain valid.
// >When omitted, this defaults to 60 seconds. For compatibility with older clients,
// >a token should never be returned with less than 60 seconds to live.
//
// [1]: https://docs.docker.com/registry/spec/auth/token/#requesting-a-token
creationTime + TimeInterval(expires_in ?? 60)
}
}
var isValid: Bool {
get {
Date() < tokenExpiresAt
}
}
}
class Registry {
var baseURL: URL
var namespace: String
var token: String? = nil
var currentAuthToken: TokenResponse? = nil
init(host: String, namespace: String) throws {
var baseURLComponents = URLComponents()
@@ -147,6 +170,11 @@ class Registry {
}
request.httpBody = body
// Invalidate token if it has expired
if currentAuthToken?.isValid == false {
currentAuthToken = nil
}
var (data, response) = try await authAwareRequest(request: request)
if response.statusCode == 401 {
@@ -199,20 +227,20 @@ class Registry {
headers["Authorization"] = "Basic \(encodedCredentials!)"
}
let (responseData, response) = try await rawRequest("GET", authenticateURL, headers: headers)
let (tokenResponseRaw, response) = try await rawRequest("GET", authenticateURL, headers: headers)
if response.statusCode != 200 {
throw RegistryError.AuthFailed(why: "received unexpected HTTP status code \(response.statusCode) "
+ "while retrieving an authentication token", details: String(decoding: responseData, as: UTF8.self))
+ "while retrieving an authentication token", details: String(decoding: tokenResponseRaw, as: UTF8.self))
}
token = try JSONDecoder().decode(TokenResponse.self, from: responseData).token
currentAuthToken = try JSONDecoder().decode(TokenResponse.self, from: tokenResponseRaw)
}
private func authAwareRequest(request: URLRequest) async throws -> (Data, HTTPURLResponse) {
var request = request
if let token = self.token {
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
if let token = currentAuthToken {
request.addValue("Bearer \(token.token)", forHTTPHeaderField: "Authorization")
}
let (responseData, response) = try await URLSession.shared.data(for: request)