├── contrib ├── packaging │ ├── config │ │ ├── finch.yaml │ │ ├── soci-snapshotter-grpc.toml │ │ ├── nerdctl.toml │ │ ├── nerdctl_ubuntu.toml │ │ ├── buildkitd.toml │ │ ├── finch.socket │ │ ├── finch-buildkit.socket │ │ ├── finch-soci.socket │ │ ├── finch-buildkit.service │ │ ├── finch-soci.service │ │ └── finch.service │ ├── deb │ │ ├── Release │ │ ├── control │ │ ├── prerm │ │ ├── postrm │ │ └── README.md │ └── rpm │ │ └── README.md └── hello-finch │ ├── go.mod │ ├── README.md │ ├── Dockerfile │ └── main.go ├── .release-please-manifest.json ├── finch.yaml.d ├── windows.yaml ├── finch-daemon-mount.yaml └── mac.yaml ├── NOTICE ├── msi-builder ├── finch.ico ├── removevm.bat ├── uninstall.bat ├── README.md └── postinstall.bat ├── config.yaml ├── pkg ├── disk │ ├── min_win_disk.zip │ └── disk.go ├── config │ ├── config_native.go │ ├── validate_natvie.go │ ├── validate_windows.go │ ├── defaults_linux.go │ ├── defaults_windows.go │ ├── config_windows.go │ ├── defaults_windows_test.go │ ├── defaults_remote_test.go │ ├── lima_config_applier_windows.go │ ├── validate_darwin.go │ ├── defaults_linux_test.go │ └── defaults_darwin.go ├── version │ └── version.go ├── path │ ├── finch_darwin.go │ ├── finch.go │ ├── finch_windows.go │ ├── finch_linux_test.go │ ├── finch_windows_test.go │ └── finch_linux.go ├── command │ ├── nerdctl_unix.go │ ├── nerdctl_windows.go │ ├── exit_error.go │ ├── exec_test.go │ ├── command.go │ ├── exit_error_test.go │ ├── exec.go │ └── nerdctl_remote.go ├── templates │ ├── templates_test.go │ └── templates.go ├── support │ ├── config_native_linux.go │ ├── config.go │ ├── config_remote.go │ └── config_test.go ├── tools.go ├── flog │ ├── level_string.go │ ├── formatter_string.go │ ├── log.go │ └── logrus.go ├── dependency │ ├── credhelper │ │ └── cred_helper_test.go │ └── vmnet │ │ └── vmnet_unix_test.go ├── fmemory │ └── fmemory.go ├── lima │ └── wrapper │ │ ├── lima_wrapper.go │ │ └── lima_wrapper_test.go ├── winutil │ └── io.go ├── mocks │ ├── pkg_fmemory_memory.go │ ├── lima_wrapper.go │ ├── pkg_config_load_system_deps.go │ ├── pkg_ssh_dialer.go │ ├── pkg_support.go │ ├── pkg_config_nerdctl_config_applier.go │ └── command_command_creator.go ├── system │ └── stdlib.go └── fssh │ └── fssh.go ├── .gitmodules ├── copyright_header ├── installer-builder ├── templates │ ├── Finch.icns │ ├── qemu.plist │ ├── manifest_pkg.yaml │ ├── manifest_executables.yaml │ ├── Info.plist │ └── entitlements.plist ├── darwin │ ├── Resources │ │ ├── banner.png │ │ ├── welcome.html │ │ ├── conclusion.html │ │ └── uninstall.sh │ ├── scripts │ │ └── postinstall │ └── distribution.xml └── tools │ ├── notarize.sh │ ├── pack-unsigned-pkg.sh │ ├── merge-back-signed-executables.sh │ └── release-installer.sh ├── .markdownlint.yaml ├── e2e ├── container │ ├── cosign_data │ │ ├── test-1.pub │ │ ├── test-2.pub │ │ ├── test-1.key │ │ └── test-2.key │ ├── container_test_other.go │ └── container_test_linux.go └── vm │ ├── install_windows_permission_check.ps1 │ ├── config_windows_test.go │ ├── vm_linux_test.go │ ├── vm_util_test.go │ ├── cred_helper_remote_test.go │ ├── install_windows_test.go │ ├── vm_test.go │ ├── daemon_darwin_test.go │ └── version_remote_test.go ├── docs ├── cmd │ ├── finch_vm_init.md │ ├── finch_vm_start.md │ ├── finch_vm_status.md │ ├── finch_logout.md │ ├── finch_top.md │ ├── finch_pause.md │ ├── finch_vm_stop.md │ ├── finch_tag.md │ ├── finch_port.md │ ├── finch_unpause.md │ ├── finch_wait.md │ ├── finch_vm_remove.md │ ├── finch_rmi.md │ ├── finch_help.md │ ├── finch_stop.md │ ├── finch_events.md │ ├── finch_kill.md │ ├── finch_version.md │ ├── finch_restart.md │ ├── finch_login.md │ ├── finch_system.md │ ├── finch_rm.md │ ├── finch_builder.md │ ├── finch_start.md │ ├── finch_history.md │ ├── finch_info.md │ ├── finch_load.md │ ├── finch_save.md │ ├── finch_volume.md │ ├── finch_network.md │ ├── finch_vm_settings.md │ ├── finch_inspect.md │ ├── finch_stats.md │ ├── finch_cp.md │ ├── finch_commit.md │ ├── finch_completion_powershell.md │ ├── finch_completion_fish.md │ ├── finch_completion_bash.md │ ├── finch_completion_zsh.md │ ├── finch_vm_disk.md │ ├── finch_exec.md │ ├── finch_ps.md │ ├── finch_support-bundle_generate.md │ ├── finch_image.md │ ├── finch_images.md │ ├── finch_update.md │ ├── finch_push.md │ ├── finch_logs.md │ ├── finch_container.md │ ├── finch_build.md │ ├── finch_compose.md │ └── finch_pull.md ├── snapshotters.md └── debug.md ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── config.yaml │ ├── feature_request.md │ └── bug_report.md ├── CODEOWNERS ├── workflows │ ├── e2e-docs.yaml │ ├── e2e-ubuntu.yaml │ ├── pkg-output-arch.yaml │ ├── canary-deb.yaml │ ├── release-please.yaml │ ├── lint-pr-title.yaml │ └── upload-msi-to-release.yaml ├── PULL_REQUEST_TEMPLATE.md └── dependabot.yaml ├── .markdownlintignore ├── cmd └── finch │ ├── support_bundle_native.go │ ├── doc.TEMPLATE │ ├── support_bundle_remote.go │ ├── version_native.go │ ├── main_darwin.go │ ├── main_windows.go │ ├── virtual_machine_disk_info.go │ ├── version_remote.go │ ├── virtual_machine_settings_windows.go │ ├── virtual_machine_windows.go │ ├── main.go │ ├── virtual_machine_disk_resize.go │ ├── virtual_machine_status.go │ ├── nerdctl_darwin.go │ └── virtual_machine_darwin.go ├── finch@.service ├── benchmark ├── vm │ └── vm_test.go ├── container │ └── container_test.go └── all │ └── all_test.go ├── scripts ├── gen-code-windows.ps1 ├── cleanup_wsl.ps1 ├── clean-iptables.sh └── canary-deb.sh ├── networks.yaml ├── .golangci.yaml ├── coverage └── coverage.go ├── winres └── winres.json └── release-please-config.json /contrib/packaging/config/finch.yaml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "1.13.0" 3 | } 4 | -------------------------------------------------------------------------------- /finch.yaml.d/windows.yaml: -------------------------------------------------------------------------------- 1 | vmType: wsl2 2 | mountType: wsl2 3 | -------------------------------------------------------------------------------- /contrib/hello-finch/go.mod: -------------------------------------------------------------------------------- 1 | module hello-finch 2 | 3 | go 1.19 4 | -------------------------------------------------------------------------------- /contrib/packaging/config/soci-snapshotter-grpc.toml: -------------------------------------------------------------------------------- 1 | namespace = "finch" 2 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Finch CLI 2 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | -------------------------------------------------------------------------------- /msi-builder/finch.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runfinch/finch/HEAD/msi-builder/finch.ico -------------------------------------------------------------------------------- /contrib/packaging/config/nerdctl.toml: -------------------------------------------------------------------------------- 1 | data_root = "/var/lib/finch/nerdctl" 2 | namespace = "finch" -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | # Every field is optional, even an empty file would work 2 | memory: 4GiB 3 | cpus: 4 4 | -------------------------------------------------------------------------------- /pkg/disk/min_win_disk.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runfinch/finch/HEAD/pkg/disk/min_win_disk.zip -------------------------------------------------------------------------------- /finch.yaml.d/finch-daemon-mount.yaml: -------------------------------------------------------------------------------- 1 | mounts: 2 | - location: "" 3 | writable: true 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "finch-core"] 2 | path = deps/finch-core 3 | url = https://github.com/runfinch/finch-core.git 4 | -------------------------------------------------------------------------------- /copyright_header: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | SPDX-License-Identifier: Apache-2.0 -------------------------------------------------------------------------------- /installer-builder/templates/Finch.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runfinch/finch/HEAD/installer-builder/templates/Finch.icns -------------------------------------------------------------------------------- /installer-builder/darwin/Resources/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/runfinch/finch/HEAD/installer-builder/darwin/Resources/banner.png -------------------------------------------------------------------------------- /contrib/packaging/config/nerdctl_ubuntu.toml: -------------------------------------------------------------------------------- 1 | data_root = "/var/lib/finch/nerdctl" 2 | namespace = "finch" 3 | cni_path = "/usr/libexec/finch/cni/bin/" 4 | -------------------------------------------------------------------------------- /contrib/hello-finch/README.md: -------------------------------------------------------------------------------- 1 | # hello, finch 2 | 3 | Say hello to Finch :wave: 4 | 5 | ```sh 6 | finch build . -t hello-finch 7 | finch run --rm hello-finch 8 | ``` 9 | -------------------------------------------------------------------------------- /contrib/packaging/config/buildkitd.toml: -------------------------------------------------------------------------------- 1 | root = "/var/lib/finch/buildkit" 2 | 3 | [worker.oci] 4 | enabled = false 5 | 6 | [worker.containerd] 7 | enabled = true 8 | namespace = "finch" 9 | -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Modern IDEs usually automatically wrap long lines in *.md files, so this may be unnecessary. 2 | line-length: false 3 | 4 | MD024: 5 | # Only check sibling headings 6 | siblings_only: true 7 | -------------------------------------------------------------------------------- /e2e/container/cosign_data/test-1.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEI+bq1hlp3SRyGIuCwOVpvAEOMdNu 3 | OVAucydf203gS17N+YtLGYQb8Q1GAPjz3B+pg7emaRSlndB44D8Bwe9zBg== 4 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /contrib/packaging/deb/Release: -------------------------------------------------------------------------------- 1 | Origin: runfinch-finch repository 2 | Label: runfinch-finch 3 | Suite: noble 4 | Codename: noble 5 | Architectures: amd64 arm64 6 | Components: main 7 | Description: https://github.com/runfinch/finch 8 | -------------------------------------------------------------------------------- /docs/cmd/finch_vm_init.md: -------------------------------------------------------------------------------- 1 | # finch vm init 2 | 3 | Initialize the virtual machine 4 | 5 | ```text 6 | finch vm init [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for init 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/cmd/finch_vm_start.md: -------------------------------------------------------------------------------- 1 | # finch vm start 2 | 3 | Start the virtual machine 4 | 5 | ```text 6 | finch vm start [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for start 13 | ``` 14 | -------------------------------------------------------------------------------- /e2e/container/cosign_data/test-2.pub: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJx6KpdJPBgARBVf4Fp778v1VWTnP 3 | 6jE7/XrpOCMkK4S+HA3s7kBOgqR/FQgybbl99eKfgNixBmLToBX/vbAzgg== 4 | -----END PUBLIC KEY----- 5 | -------------------------------------------------------------------------------- /docs/cmd/finch_vm_status.md: -------------------------------------------------------------------------------- 1 | # finch vm status 2 | 3 | Status of the virtual machine 4 | 5 | ```text 6 | finch vm status [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for status 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/cmd/finch_logout.md: -------------------------------------------------------------------------------- 1 | # finch logout 2 | 3 | Log out from a container registry 4 | 5 | ```text 6 | finch logout [flags] [SERVER] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for logout 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/cmd/finch_top.md: -------------------------------------------------------------------------------- 1 | # finch top 2 | 3 | Display the running processes of a container 4 | 5 | ```text 6 | finch top CONTAINER [ps OPTIONS] [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for top 13 | ``` 14 | -------------------------------------------------------------------------------- /contrib/packaging/config/finch.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Socket for finch daemon 3 | 4 | [Socket] 5 | ListenStream=/run/finch.sock 6 | SocketMode=0660 7 | SocketUser=root 8 | SocketGroup=root 9 | 10 | [Install] 11 | WantedBy=sockets.target 12 | -------------------------------------------------------------------------------- /docs/cmd/finch_pause.md: -------------------------------------------------------------------------------- 1 | # finch pause 2 | 3 | Pause all processes within one or more containers 4 | 5 | ```text 6 | finch pause [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for pause 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/cmd/finch_vm_stop.md: -------------------------------------------------------------------------------- 1 | # finch vm stop 2 | 3 | Stop the virtual machine 4 | 5 | ```text 6 | finch vm stop [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -f, --force forcibly stop finch VM 13 | -h, --help help for stop 14 | ``` 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _output/ 2 | *.idea 3 | git-diff 4 | *.DS_Store 5 | *.bak 6 | _vde_output/ 7 | **/*.tar.gz 8 | **/*.lz4 9 | **/*.img 10 | tmp/ 11 | .vscode/ 12 | tools_bin/ 13 | test-coverage.* 14 | *.syso 15 | msi-builder/build/ 16 | contrib/packaging/rpm/rpmbuild 17 | -------------------------------------------------------------------------------- /docs/cmd/finch_tag.md: -------------------------------------------------------------------------------- 1 | # finch tag 2 | 3 | Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE 4 | 5 | ```text 6 | finch tag [flags] SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for tag 13 | ``` 14 | -------------------------------------------------------------------------------- /msi-builder/removevm.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SET InstallDir=%~1 3 | 4 | :: Stop and remove any running instance 5 | finch.exe vm stop -f ^ & 6 | finch.exe vm remove -f ^ & 7 | 8 | :: Just in case 9 | wsl --terminate lima-finch ^ & 10 | wsl --unregister lima-finch 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yaml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/runfinch/finch/discussions 5 | about: Use GitHub Discussions to ask questions, discuss options, or propose new ideas 6 | 7 | -------------------------------------------------------------------------------- /docs/cmd/finch_port.md: -------------------------------------------------------------------------------- 1 | # finch port 2 | 3 | List port mappings or a specific mapping for the container 4 | 5 | ```text 6 | finch port [flags] CONTAINER [PRIVATE_PORT[/PROTO]] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for port 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/cmd/finch_unpause.md: -------------------------------------------------------------------------------- 1 | # finch unpause 2 | 3 | Unpause all processes within one or more containers 4 | 5 | ```text 6 | finch unpause [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for unpause 13 | ``` 14 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # CHANGELOG generated by release-please action has to be approved by release-approvers before creating a release. 2 | /CHANGELOG.md @runfinch/release-approvers 3 | 4 | # Any changes to github workflows requires dev-team approval 5 | /.github/ @runfinch/dev-team 6 | -------------------------------------------------------------------------------- /docs/cmd/finch_wait.md: -------------------------------------------------------------------------------- 1 | # finch wait 2 | 3 | Block until one or more containers stop, then print their exit codes. 4 | 5 | ```text 6 | finch wait [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for wait 13 | ``` 14 | -------------------------------------------------------------------------------- /e2e/vm/install_windows_permission_check.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true)] 3 | $Path 4 | ) 5 | 6 | $includeExplicit = $true 7 | $includeInherited = $false 8 | (Get-Acl $PATH).GetAccessRules($includeExplicit, $includeInherited, [System.Security.Principal.NTAccount]) 9 | -------------------------------------------------------------------------------- /.github/workflows/e2e-docs.yaml: -------------------------------------------------------------------------------- 1 | name: e2e-docs 2 | on: 3 | workflow_call: 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | timeout-minutes: 2 9 | steps: 10 | - name: Skip 11 | run: | 12 | echo "Skipping CI for docs & contrib files" 13 | -------------------------------------------------------------------------------- /docs/cmd/finch_vm_remove.md: -------------------------------------------------------------------------------- 1 | # finch vm remove 2 | 3 | Remove the virtual machine instance 4 | 5 | ```text 6 | finch vm remove [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -f, --force forcibly remove finch VM 13 | -h, --help help for remove 14 | ``` 15 | -------------------------------------------------------------------------------- /contrib/hello-finch/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/docker/library/golang:1.19 AS builder 2 | WORKDIR /build 3 | COPY . . 4 | 5 | RUN CGO_ENABLED=0 go build -a -o hello-finch . 6 | 7 | FROM scratch 8 | COPY --from=builder /build/hello-finch /app/ 9 | WORKDIR /app 10 | ENTRYPOINT ["./hello-finch"] 11 | -------------------------------------------------------------------------------- /installer-builder/templates/qemu.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.hypervisor 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/cmd/finch_rmi.md: -------------------------------------------------------------------------------- 1 | # finch rmi 2 | 3 | Remove one or more images 4 | 5 | ```text 6 | finch rmi [flags] IMAGE [IMAGE, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --async Asynchronous mode 13 | -f, --force Force removal of the image 14 | -h, --help help for rmi 15 | ``` 16 | -------------------------------------------------------------------------------- /contrib/packaging/config/finch-buildkit.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=BuildKit (for Finch) 3 | PartOf=finch.service 4 | Documentation=https://github.com/moby/buildkit 5 | 6 | [Socket] 7 | ListenStream=/var/lib/finch/buildkit/buildkitd.sock 8 | SocketMode=0660 9 | 10 | [Install] 11 | WantedBy=sockets.target 12 | -------------------------------------------------------------------------------- /docs/cmd/finch_help.md: -------------------------------------------------------------------------------- 1 | # finch help 2 | 3 | Help provides help for any command in the application. 4 | Simply type finch help [path to command] for full details. 5 | 6 | ```text 7 | finch help [command] [flags] 8 | ``` 9 | 10 | ## Options 11 | 12 | ```text 13 | -h, --help help for help 14 | ``` 15 | -------------------------------------------------------------------------------- /installer-builder/templates/manifest_pkg.yaml: -------------------------------------------------------------------------------- 1 | type: :app 2 | os: :osx 3 | name: Finch.pkg 4 | outputs: 5 | - label: macos 6 | path: Finch.pkg 7 | app: 8 | :identifier: com.amazon.aws.finch 9 | signing_requirements: 10 | certificate_type: :developerIDInstallerDistribution 11 | app_id_prefix: 94KV3E626L -------------------------------------------------------------------------------- /docs/cmd/finch_stop.md: -------------------------------------------------------------------------------- 1 | # finch stop 2 | 3 | Stop one or more running containers 4 | 5 | ```text 6 | finch stop [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for stop 13 | -t, --time int Seconds to wait before sending a SIGKILL (default 10) 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/cmd/finch_events.md: -------------------------------------------------------------------------------- 1 | # finch events 2 | 3 | Get real time events from the server 4 | 5 | ```text 6 | finch events [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --format string Format the output using the given Go template, e.g, '{{json .}}' 13 | -h, --help help for events 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/cmd/finch_kill.md: -------------------------------------------------------------------------------- 1 | # finch kill 2 | 3 | Kill one or more running containers 4 | 5 | ```text 6 | finch kill [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for kill 13 | -s, --signal string Signal to send to the container (default "KILL") 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/cmd/finch_version.md: -------------------------------------------------------------------------------- 1 | # finch version 2 | 3 | Shows Finch version information 4 | 5 | ```text 6 | finch version [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -f, --format string Format the output using the given Go template, e.g, '{{json .}}' 13 | -h, --help help for version 14 | ``` 15 | -------------------------------------------------------------------------------- /pkg/config/config_native.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package config 7 | 8 | // Finch represents the configuration file for Finch CLI. 9 | type Finch struct { 10 | SharedSettings `yaml:",inline"` 11 | } 12 | -------------------------------------------------------------------------------- /contrib/packaging/config/finch-soci.socket: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=SOCI snapshotter (for Finch) 3 | PartOf=finch.service 4 | Documentation=https://github.com/awslabs/soci-snapshotter 5 | 6 | [Socket] 7 | ListenStream=/var/lib/finch/soci/soci-snapshotter-grpc.sock 8 | SocketMode=0660 9 | 10 | [Install] 11 | WantedBy=sockets.target 12 | -------------------------------------------------------------------------------- /docs/cmd/finch_restart.md: -------------------------------------------------------------------------------- 1 | # finch restart 2 | 3 | Restart one or more running containers 4 | 5 | ```text 6 | finch restart [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for restart 13 | -t, --time uint Seconds to wait for stop before killing it (default 10) 14 | ``` 15 | -------------------------------------------------------------------------------- /e2e/vm/config_windows_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //go:build windows 4 | 5 | package vm 6 | 7 | import ( 8 | "os" 9 | "path/filepath" 10 | ) 11 | 12 | var finchConfigFilePath = filepath.Join(os.Getenv("LOCALAPPDATA"), ".finch", "finch.yaml") 13 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Issue #, if available: 2 | 3 | *Description of changes:* 4 | 5 | *Testing done:* 6 | 7 | 8 | 9 | - [ ] I've reviewed the guidance in CONTRIBUTING.md 10 | 11 | 12 | #### License Acceptance 13 | 14 | By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. 15 | -------------------------------------------------------------------------------- /installer-builder/tools/notarize.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit 3 | set -o pipefail 4 | 5 | #$1: the account name 6 | #$2: the credential 7 | cd ./installer-builder/output/installer/signed/Payload 8 | ditto -c -k --sequesterRsrc --keepParent Finch.pkg Finch.zip 9 | xcrun notarytool submit Finch.zip --apple-id "${1}" --password "${2}" --team-id 94KV3E626L --wait -------------------------------------------------------------------------------- /contrib/packaging/deb/control: -------------------------------------------------------------------------------- 1 | Source: runfinch-finch 2 | Section: devel 3 | Priority: optional 4 | Maintainer: AWS finch-package-maintainers@amazon.com 5 | Build-Depends: debhelper (>= 13) 6 | Homepage: https://runfinch.com 7 | Package: runfinch-finch 8 | Architecture: ${ARCH} 9 | Depends: ${REQUIREMENTS} 10 | Description: https://github.com/runfinch/finch 11 | -------------------------------------------------------------------------------- /docs/cmd/finch_login.md: -------------------------------------------------------------------------------- 1 | # finch login 2 | 3 | Log in to a container registry 4 | 5 | ```text 6 | finch login [flags] [SERVER] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -h, --help help for login 13 | -p, --password string Password 14 | --password-stdin Take the password from stdin 15 | -u, --username string Username 16 | ``` 17 | -------------------------------------------------------------------------------- /.markdownlintignore: -------------------------------------------------------------------------------- 1 | deps/ 2 | # Since the current documentation generation works by just capturing stdout, we don't do any post processing 3 | # The completion files have issues with code block style 4 | docs/cmd/*completion*.md 5 | # finch_logs.md has issues with the list not being surrounded by newlines 6 | docs/cmd/finch_logs.md 7 | # build artifacts 8 | contrib/packaging/rpm/rpmbuild -------------------------------------------------------------------------------- /docs/cmd/finch_system.md: -------------------------------------------------------------------------------- 1 | # finch system 2 | 3 | Manage containerd 4 | 5 | ```text 6 | finch system [flags] 7 | ``` 8 | 9 | ## Commands 10 | 11 | ```text 12 | events Get real time events from the server 13 | info Display system-wide information 14 | prune Remove unused data 15 | ``` 16 | 17 | ## Options 18 | 19 | ```text 20 | -h, --help help for system 21 | ``` 22 | -------------------------------------------------------------------------------- /msi-builder/uninstall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SET InstallDir=%~1 3 | 4 | :: Stop and remove any running instance 5 | finch.exe vm stop -f ^ & 6 | finch.exe vm remove -f ^ & 7 | 8 | :: Just in case 9 | wsl --terminate lima-finch ^ & 10 | wsl --unregister lima-finch 11 | 12 | :: Delete files and directories if they exist 13 | if exist "%InstallDir%\lima\" rmdir /s /q "%InstallDir%\lima\" -------------------------------------------------------------------------------- /pkg/version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package version contains generated version number from GO build 5 | package version 6 | 7 | // Version will be filled via Makefile. 8 | var ( 9 | Version string 10 | // GitCommit is filled via Makefile. 11 | GitCommit string 12 | ) 13 | -------------------------------------------------------------------------------- /docs/cmd/finch_rm.md: -------------------------------------------------------------------------------- 1 | # finch rm 2 | 3 | Remove one or more containers 4 | 5 | ```text 6 | finch rm [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -f, --force Force the removal of a running|paused|unknown container (uses SIGKILL) 13 | -h, --help help for rm 14 | -v, --volumes Remove volumes associated with the container 15 | ``` 16 | -------------------------------------------------------------------------------- /contrib/packaging/config/finch-buildkit.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=BuildKit (for Finch) 3 | Requires=finch-buildkit.socket 4 | After=finch-buildkit.socket 5 | PartOf=finch.service 6 | Documentation=https://github.com/moby/buildkit 7 | 8 | [Service] 9 | ExecStart=/usr/libexec/finch/buildkitd --config /etc/finch/buildkit/buildkitd.toml --addr fd:// 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /docs/cmd/finch_builder.md: -------------------------------------------------------------------------------- 1 | # finch builder 2 | 3 | Manage builds 4 | 5 | ```text 6 | finch builder [flags] 7 | ``` 8 | 9 | ## Commands 10 | 11 | ```text 12 | build Build an image from a Dockerfile. Needs buildkitd to be running. 13 | debug Debug Dockerfile 14 | prune Clean up BuildKit build cache 15 | ``` 16 | 17 | ## Options 18 | 19 | ```text 20 | -h, --help help for builder 21 | ``` 22 | -------------------------------------------------------------------------------- /e2e/container/container_test_other.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !linux 5 | 6 | // Package container runs tests related to container development. 7 | package container 8 | 9 | import ( 10 | "github.com/runfinch/common-tests/tests" 11 | ) 12 | 13 | func getCGroupMode() tests.CGMode { 14 | return 0 15 | } 16 | -------------------------------------------------------------------------------- /docs/cmd/finch_start.md: -------------------------------------------------------------------------------- 1 | # finch start 2 | 3 | Start one or more running containers 4 | 5 | ```text 6 | finch start [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -a, --attach Attach STDOUT/STDERR and forward signals 13 | --detach-keys string Override the default detach keys (default "ctrl-p,ctrl-q") 14 | -h, --help help for start 15 | ``` 16 | -------------------------------------------------------------------------------- /pkg/config/validate_natvie.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package config 7 | 8 | import ( 9 | "github.com/runfinch/finch/pkg/flog" 10 | "github.com/runfinch/finch/pkg/fmemory" 11 | ) 12 | 13 | func validate(_ *Finch, _ flog.Logger, _ LoadSystemDeps, _ fmemory.Memory) error { 14 | return nil 15 | } 16 | -------------------------------------------------------------------------------- /docs/cmd/finch_history.md: -------------------------------------------------------------------------------- 1 | # finch history 2 | 3 | Show the history of an image 4 | 5 | ```text 6 | finch history [flags] IMAGE 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -f, --format string Format the output using the given Go template, e.g, '{{json .}}' 13 | -h, --help help for history 14 | --no-trunc Don't truncate output 15 | -q, --quiet Only show numeric IDs 16 | ``` 17 | -------------------------------------------------------------------------------- /pkg/config/validate_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package config 7 | 8 | import ( 9 | "github.com/runfinch/finch/pkg/flog" 10 | "github.com/runfinch/finch/pkg/fmemory" 11 | ) 12 | 13 | func validate(_ *Finch, _ flog.Logger, _ LoadSystemDeps, _ fmemory.Memory) error { 14 | return nil 15 | } 16 | -------------------------------------------------------------------------------- /contrib/packaging/config/finch-soci.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=soci-snapshotter-grpc (for Finch) 3 | PartOf=finch.service 4 | Requires=finch-soci.socket 5 | After=finch-soci.socket 6 | Documentation=https://github.com/awslabs/soci-snapshotter 7 | 8 | [Service] 9 | ExecStart=/usr/libexec/finch/soci-snapshotter-grpc --config /etc/finch/soci/soci-snapshotter-grpc.toml --root /var/lib/finch/soci 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /installer-builder/templates/manifest_executables.yaml: -------------------------------------------------------------------------------- 1 | type: :app 2 | os: :osx 3 | name: EXECUTABLES_TO_SIGN 4 | outputs: 5 | - label: macos 6 | path: EXECUTABLES_TO_SIGN 7 | app: 8 | :identifier: com.amazon.aws.finch 9 | signing_requirements: 10 | certificate_type: :developerIDAppDistribution 11 | app_id_prefix: 94KV3E626L 12 | signing_args: 13 | entitlements_path: SIGNING_METADATA/entitlements.plist 14 | embedded_requirements: 15 | -------------------------------------------------------------------------------- /docs/cmd/finch_info.md: -------------------------------------------------------------------------------- 1 | # finch info 2 | 3 | Display system-wide information 4 | 5 | ```text 6 | finch info [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -f, --format string Format the output using the given Go template, e.g, '{{json .}}' 13 | -h, --help help for info 14 | --mode string Information mode, "dockercompat" for Docker-compatible output, "native" for containerd-native output (default "dockercompat") 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/cmd/finch_load.md: -------------------------------------------------------------------------------- 1 | # finch load 2 | 3 | Supports both Docker Image Spec v1.2 and OCI Image Spec v1.0. 4 | 5 | ```text 6 | finch load [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --all-platforms Import content for all platforms 13 | -h, --help help for load 14 | -i, --input string Read from tar archive file, instead of STDIN 15 | --platform strings Import content for a specific platform 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/cmd/finch_save.md: -------------------------------------------------------------------------------- 1 | # finch save 2 | 3 | The archive implements both Docker Image Spec v1.2 and OCI Image Spec v1.0. 4 | 5 | ```text 6 | finch save [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --all-platforms Export content for all platforms 13 | -h, --help help for save 14 | -o, --output string Write to a file, instead of STDOUT 15 | --platform strings Export content for a specific platform 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/cmd/finch_volume.md: -------------------------------------------------------------------------------- 1 | # finch volume 2 | 3 | Manage volumes 4 | 5 | ```text 6 | finch volume [flags] 7 | ``` 8 | 9 | ## Commands 10 | 11 | ```text 12 | create Create a volume 13 | inspect Display detailed information on one or more volumes 14 | ls List volumes 15 | prune Remove all unused local volumes 16 | rm Remove one or more volumes 17 | ``` 18 | 19 | ## Options 20 | 21 | ```text 22 | -h, --help help for volume 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/cmd/finch_network.md: -------------------------------------------------------------------------------- 1 | # finch network 2 | 3 | Manage networks 4 | 5 | ```text 6 | finch network [flags] 7 | ``` 8 | 9 | ## Commands 10 | 11 | ```text 12 | create Create a network 13 | inspect Display detailed information on one or more networks 14 | ls List networks 15 | prune Remove all unused networks 16 | rm Remove one or more networks 17 | ``` 18 | 19 | ## Options 20 | 21 | ```text 22 | -h, --help help for network 23 | ``` 24 | -------------------------------------------------------------------------------- /pkg/path/finch_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package path 7 | 8 | // FinchRootDir returns the path to the Finch root directory, which is $HOME on UNIX. 9 | func (Finch) FinchRootDir(ffd FinchFinderDeps) (string, error) { 10 | home, err := ffd.GetUserHome() 11 | if err != nil { 12 | return "", err 13 | } 14 | 15 | return home, nil 16 | } 17 | -------------------------------------------------------------------------------- /cmd/finch/support_bundle_native.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package main 7 | 8 | // canCreateBundle returns an error if there's any issue preventing creating of 9 | // a support bundle. 10 | // This is used in "remote" mode to gate creation to the VM being online. 11 | func (gsa *generateSupportBundleAction) canCreateBundle() error { 12 | return nil 13 | } 14 | -------------------------------------------------------------------------------- /e2e/container/container_test_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | // Package container runs tests related to container development. 7 | package container 8 | 9 | import ( 10 | "github.com/containerd/cgroups" 11 | "github.com/runfinch/common-tests/tests" 12 | ) 13 | 14 | func getCGroupMode() tests.CGMode { 15 | cgMode := cgroups.Mode() 16 | return tests.CGMode(cgMode) 17 | } 18 | -------------------------------------------------------------------------------- /docs/cmd/finch_vm_settings.md: -------------------------------------------------------------------------------- 1 | # finch vm settings 2 | 3 | Configure the virtual machine instance 4 | 5 | ```text 6 | finch vm settings [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --cpus int the amount of vCPU to dedicate to the virtual machine (restart the vm when applying this change.) 13 | -h, --help help for settings 14 | --memory string the amount of memory to dedicate to the virtual machine (restart the vm when applying this change.) 15 | ``` 16 | -------------------------------------------------------------------------------- /installer-builder/tools/pack-unsigned-pkg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit 3 | set -o pipefail 4 | 5 | createUnsignedPkgTarball() { 6 | #prepare unsigned .pkg into .tar 7 | cp -a ./installer-builder/templates/manifest_pkg.yaml ./installer-builder/output/installer/unsigned/package/manifest.yaml 8 | cd ./installer-builder/output/installer/unsigned/package 9 | tar -cvzf artifact.gz -C artifact . 10 | tar -cvzf ../package.tar.gz manifest.yaml artifact.gz 11 | } 12 | 13 | createUnsignedPkgTarball -------------------------------------------------------------------------------- /finch@.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Finch daemon %I 3 | Documentation=https://runfinch.com https://github.com/runfinch/finch-daemon 4 | After=network.target local-fs.target containerd.service buildkit.service 5 | 6 | [Service] 7 | ExecStart=/usr/local/bin/finch-daemon --socket-owner %i 8 | ExecStartPost=-rm -rf /var/run/docker.sock 9 | ExecStartPost=ln -s /run/finch.sock /var/run/docker.sock 10 | Type=notify 11 | Delegate=yes 12 | Restart=always 13 | RestartSec=5 14 | 15 | [Install] 16 | WantedBy=multi-user.target 17 | -------------------------------------------------------------------------------- /pkg/command/nerdctl_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build !windows 5 | 6 | package command 7 | 8 | // EnvKeyPath is the name of the PATH environment variable. 9 | // EnvKeyPathJoiner is the "joiner" between directories in a PATH string. 10 | // These are exported to facilitate unit testing, since it uses a different package (command_test). 11 | const ( 12 | EnvKeyPath = "PATH" 13 | EnvKeyPathJoiner = ":" 14 | ) 15 | -------------------------------------------------------------------------------- /pkg/command/nerdctl_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package command 7 | 8 | // EnvKeyPath is the name of the PATH environment variable. 9 | // EnvKeyPathJoiner is the "joiner" between directories in a PATH string. 10 | // These are exported to facilitate unit testing, since it uses a different package (command_test). 11 | const ( 12 | EnvKeyPath = "Path" 13 | EnvKeyPathJoiner = `\;` 14 | ) 15 | -------------------------------------------------------------------------------- /docs/cmd/finch_inspect.md: -------------------------------------------------------------------------------- 1 | # finch inspect 2 | 3 | Return low-level information on objects. 4 | 5 | ```text 6 | finch inspect [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -f, --format string Format the output using the given Go template, e.g, '{{json .}}' 13 | -h, --help help for inspect 14 | --mode string Inspect mode, "dockercompat" for Docker-compatible output, "native" for containerd-native output (default "dockercompat") 15 | --type string Return JSON for specified type 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/cmd/finch_stats.md: -------------------------------------------------------------------------------- 1 | # finch stats 2 | 3 | Display a live stream of container(s) resource usage statistics. 4 | 5 | ```text 6 | finch stats [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -a, --all Show all containers (default shows just running) 13 | --format string Pretty-print images using a Go template, e.g, '{{json .}}' 14 | -h, --help help for stats 15 | --no-stream Disable streaming stats and only pull the first result 16 | --no-trunc Do not truncate output 17 | ``` 18 | -------------------------------------------------------------------------------- /pkg/config/defaults_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package config 7 | 8 | import ( 9 | "github.com/runfinch/finch/pkg/command" 10 | "github.com/runfinch/finch/pkg/fmemory" 11 | ) 12 | 13 | // applyDefaults sets default configuration options if they are not already set. 14 | func applyDefaults( 15 | cfg *Finch, 16 | _ LoadSystemDeps, 17 | _ fmemory.Memory, 18 | _ command.Creator, 19 | ) *Finch { 20 | return cfg 21 | } 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest a new feature for Finch 4 | title: '' 5 | labels: 'feature' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **What is the problem you're trying to solve?.** 11 | A clear and concise description of the use case for this feature. Please provide an example, if possible. 12 | 13 | 14 | **Describe the feature you'd like** 15 | A clear and concise description of what you'd like to happen. 16 | 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. -------------------------------------------------------------------------------- /docs/cmd/finch_cp.md: -------------------------------------------------------------------------------- 1 | # finch cp 2 | 3 | Copy files/folders between a running container and the local filesystem. 4 | This command requires 'tar' to be installed on the host (not in the container). 5 | Using GNU tar is recommended. 6 | The path of the 'tar' binary can be specified with an environment variable '$TAR'. 7 | 8 | ```text 9 | finch cp [flags] CONTAINER:SRC_PATH DEST_PATH|- 10 | finch cp [flags] SRC_PATH|- CONTAINER:DEST_PATH 11 | ``` 12 | 13 | ## Options 14 | 15 | ```text 16 | -L, --follow-link Always follow symbolic link in SRC_PATH. 17 | -h, --help help for cp 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/cmd/finch_commit.md: -------------------------------------------------------------------------------- 1 | # finch commit 2 | 3 | Create a new image from a container's changes 4 | 5 | ```text 6 | finch commit [flags] CONTAINER REPOSITORY[:TAG] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -a, --author string Author (e.g., "finch contributor ") 13 | -c, --change stringArray Apply Dockerfile instruction to the created image (supported directives: [CMD, ENTRYPOINT]) 14 | -h, --help help for commit 15 | -m, --message string Commit message 16 | -p, --pause Pause container during commit (default true) 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/cmd/finch_completion_powershell.md: -------------------------------------------------------------------------------- 1 | # finch completion powershell 2 | 3 | Generate the autocompletion script for powershell. 4 | 5 | To load completions in your current shell session: 6 | 7 | finch completion powershell | Out-String | Invoke-Expression 8 | 9 | To load completions for every new session, add the output of the above command 10 | to your powershell profile. 11 | 12 | ```text 13 | finch completion powershell [flags] 14 | ``` 15 | 16 | ## Options 17 | 18 | ```text 19 | -h, --help help for powershell 20 | --no-descriptions disable completion descriptions 21 | ``` 22 | -------------------------------------------------------------------------------- /pkg/templates/templates_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package templates 5 | 6 | import ( 7 | "bytes" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestNew(t *testing.T) { 14 | t.Parallel() 15 | 16 | tag := "TestNew" 17 | tmpl, err := New(tag).Parse(`{{json .Os}}`) 18 | assert.Nil(t, err) 19 | 20 | var b bytes.Buffer 21 | assert.Nil(t, tmpl.Execute(&b, map[string]string{"Os": "linux"})) 22 | 23 | want := "\"linux\"" 24 | assert.Equal(t, want, b.String()) 25 | } 26 | -------------------------------------------------------------------------------- /.github/workflows/e2e-ubuntu.yaml: -------------------------------------------------------------------------------- 1 | name: e2e-ubuntu 2 | on: 3 | workflow_call: 4 | inputs: 5 | arch: 6 | type: string 7 | required: true 8 | output-arch: 9 | type: string 10 | required: true 11 | 12 | jobs: 13 | e2e-ubuntu-finch: 14 | uses: ./.github/workflows/e2e-ubuntu-finch.yaml 15 | with: 16 | arch: ${{ inputs.arch }} 17 | output-arch: ${{ inputs.output-arch }} 18 | 19 | e2e-ubuntu-finch-daemon: 20 | uses: ./.github/workflows/e2e-ubuntu-finch-daemon.yaml 21 | with: 22 | arch: ${{ inputs.arch }} 23 | output-arch: ${{ inputs.output-arch }} 24 | -------------------------------------------------------------------------------- /installer-builder/darwin/Resources/welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 |
9 |

This installer will guide you through the steps to install Finch __VERSION__ on your computer.

10 |
11 |

Click “Continue" to continue the next step.

12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/cmd/finch_completion_fish.md: -------------------------------------------------------------------------------- 1 | # finch completion fish 2 | 3 | Generate the autocompletion script for the fish shell. 4 | 5 | To load completions in your current shell session: 6 | 7 | finch completion fish | source 8 | 9 | To load completions for every new session, execute once: 10 | 11 | finch completion fish > ~/.config/fish/completions/finch.fish 12 | 13 | You will need to start a new shell for this setup to take effect. 14 | 15 | ```text 16 | finch completion fish [flags] 17 | ``` 18 | 19 | ## Options 20 | 21 | ```text 22 | -h, --help help for fish 23 | --no-descriptions disable completion descriptions 24 | ``` 25 | -------------------------------------------------------------------------------- /pkg/support/config_native_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package support 7 | 8 | func (bc *bundleConfig) LogFiles() []string { 9 | // TODO: add support for dumping logs from journalctl? 10 | files := []string{} 11 | return files 12 | } 13 | 14 | func (bc *bundleConfig) ConfigFiles() []string { 15 | return []string{ 16 | bc.finch.ConfigFilePath(), 17 | } 18 | } 19 | 20 | func (bc *bundleConfig) JournalServices() []string { 21 | return []string{"service:containerd", "service:finch", "service:buildkit", "service:soci"} 22 | } 23 | -------------------------------------------------------------------------------- /contrib/packaging/deb/prerm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Stop all Finch services before removing the package 5 | systemctl stop finch.socket || true 6 | systemctl stop finch.service || true 7 | systemctl stop finch-buildkit.service || true 8 | systemctl stop finch-soci.service || true 9 | 10 | # Disable services to prevent them from starting on boot 11 | systemctl disable finch.service || true 12 | systemctl disable finch-buildkit.service || true 13 | systemctl disable finch-soci.service || true 14 | systemctl disable finch.socket || true 15 | systemctl disable finch-buildkit.socket || true 16 | systemctl disable finch-soci.socket || true 17 | 18 | exit 0 19 | -------------------------------------------------------------------------------- /docs/cmd/finch_completion_bash.md: -------------------------------------------------------------------------------- 1 | # finch completion bash 2 | 3 | Generate the autocompletion script for the bash shell. 4 | 5 | This script depends on the 'bash-completion' package. 6 | If it is not installed already, you can install it via your OS's package manager. 7 | 8 | To load completions in your current shell session: 9 | 10 | source <(finch completion bash) 11 | 12 | To load completions for every new session, execute once: 13 | 14 | #### 15 | 16 | ```text 17 | finch completion bash 18 | ``` 19 | 20 | ## Options 21 | 22 | ```text 23 | -h, --help help for bash 24 | --no-descriptions disable completion descriptions 25 | ``` 26 | -------------------------------------------------------------------------------- /benchmark/vm/vm_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package vm runs benchmark tests related to the virtual machine of Finch. 5 | package vm 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/runfinch/finch/benchmark" 11 | ) 12 | 13 | func BenchmarkVM(b *testing.B) { 14 | suite := &benchmark.Suite{} 15 | err := suite.Setup() 16 | if err != nil { 17 | b.Fatal(err) 18 | } 19 | 20 | b.Run("BenchmarkVMInit", func(b *testing.B) { 21 | suite.BenchmarkVMInit(b) 22 | }) 23 | 24 | b.Run("BenchmarkVMStart", func(b *testing.B) { 25 | suite.BenchmarkVMStart(b) 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/finch/doc.TEMPLATE: -------------------------------------------------------------------------------- 1 | # {{ .CmdPath }} 2 | 3 | {{if gt (len .Description) 0}}{{ .Description }} 4 | 5 | {{end}}{{if gt (len .Properties) 0}}## Properties 6 | 7 | {{.Properties}} 8 | 9 | {{end}}```text 10 | {{ .Usage }} 11 | ```{{if gt (len .Aliases) 0}} 12 | 13 | ## Aliases 14 | 15 | {{.Aliases}} 16 | {{end}}{{if gt (len .Examples) 0}} 17 | 18 | ## Examples 19 | 20 | {{.Examples}} 21 | {{end}}{{if gt (len .Commands) 0}} 22 | 23 | ## Commands 24 | 25 | ```text 26 | {{ .Commands }} 27 | ```{{end}}{{if gt (len .Options) 0}} 28 | 29 | ## Options 30 | 31 | ```text 32 | {{ .Options }} 33 | ```{{end}}{{if gt (len .SeeAlso) 0}} 34 | 35 | ## SEE ALSO 36 | 37 | {{ .SeeAlso }} 38 | {{end}} 39 | -------------------------------------------------------------------------------- /.github/workflows/pkg-output-arch.yaml: -------------------------------------------------------------------------------- 1 | name: get-output-arch 2 | on: 3 | workflow_call: 4 | inputs: 5 | arch: 6 | type: string 7 | required: true 8 | 9 | jobs: 10 | get-output-arch: 11 | outputs: 12 | arch: ${{ steps.output-arch.arch }} 13 | runs-on: ubuntu-latest 14 | timeout-minutes: 2 15 | steps: 16 | - name: 'get output arch' 17 | id: output-arch 18 | run: | 19 | shopt -s nocasematch 20 | if [[ ${{ inputs.arch }} == "amd64" ]]; then 21 | echo "arch=x86_64" >> "$GITHUB_OUTPUT" 22 | elif [[ ${{ inputs.arch }} == "arm64" ]]; then 23 | echo "arch=aarch64" >> "$GITHUB_OUTPUT" 24 | fi 25 | -------------------------------------------------------------------------------- /docs/cmd/finch_completion_zsh.md: -------------------------------------------------------------------------------- 1 | # finch completion zsh 2 | 3 | Generate the autocompletion script for the zsh shell. 4 | 5 | If shell completion is not already enabled in your environment you will need 6 | to enable it. You can execute the following once: 7 | 8 | echo "autoload -U compinit; compinit" >> ~/.zshrc 9 | 10 | To load completions in your current shell session: 11 | 12 | source <(finch completion zsh) 13 | 14 | To load completions for every new session, execute once: 15 | 16 | #### 17 | 18 | ```text 19 | finch completion zsh [flags] 20 | ``` 21 | 22 | ## Options 23 | 24 | ```text 25 | -h, --help help for zsh 26 | --no-descriptions disable completion descriptions 27 | ``` 28 | -------------------------------------------------------------------------------- /e2e/container/cosign_data/test-1.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY----- 2 | eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjo2NTUzNiwiciI6 3 | OCwicCI6MX0sInNhbHQiOiJtaGFxWTNwdEdoWlV2VE9ESXZQaGFxeEhPdmJrRmdt 4 | Vk9RUk5DQ0Y2ckVJPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 5 | Iiwibm9uY2UiOiJkenVqeFRZdldkNjJ2em9OUU12MDRvQkk3M24yMHlmTiJ9LCJj 6 | aXBoZXJ0ZXh0IjoiN1ZPMC9VNVhqT1VTdnNTeHZwYi9TOGFGSGlFWFo1bGdwQlZr 7 | dGxKSHdsTjNZdnZJM29CK3p2d3hTbElSRDRVOGlhVHBhL3Q5TlFhSVRHdFVrWUo3 8 | NGtFMm5rZ2FEZFV3QjJ2WDM1RG1JaXB2VGx6TFZ6cmVBcVR5QkNUQkZnMzVPL294 9 | RWJrT2dzSVFrUkRLQmlNWlgzT1BxMUZlNUM1cS95QVZaUzZVQThLUDJNSkNDVnFn 10 | WUoxay9kZlRFU0JyOC9iWkM4MEl6WU9QL2c9PSJ9 11 | -----END ENCRYPTED SIGSTORE PRIVATE KEY----- -------------------------------------------------------------------------------- /pkg/tools.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build tools 5 | 6 | package pkg 7 | 8 | // Ensure that everyone working on this project uses the same version of the following Go-based tools. 9 | // 10 | // For the tutorial to add a new tool, see https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module. 11 | // After following the tutorial, update `download-licenses` in Makefile. You'll likely also need to update `gen-code`. 12 | import ( 13 | _ "github.com/google/go-licenses" 14 | _ "github.com/tc-hib/go-winres" 15 | _ "go.uber.org/mock/mockgen" 16 | _ "golang.org/x/tools/cmd/stringer" 17 | ) 18 | -------------------------------------------------------------------------------- /e2e/container/cosign_data/test-2.key: -------------------------------------------------------------------------------- 1 | -----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY----- 2 | eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjo2NTUzNiwiciI6 3 | OCwicCI6MX0sInNhbHQiOiJFaWV0cE5zeEV5U1dBeTJEeHIreGtsdVZiaDIvQWNi 4 | dVd0WXg2aG1tU3QwPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 5 | Iiwibm9uY2UiOiJnVEJDa3I4VDVGNlQ2SGRzWWFqU09vWURJSU5LTTU0diJ9LCJj 6 | aXBoZXJ0ZXh0IjoicHJ4NTJhVDQ3N3VNUmtIOEs2akVSRDd2RzBlMEZoNlBCcjVi 7 | eC9tR3BHejg0QjIvbVA5bU0xQnJidTEzKzNha3doTjlhbFpPR0xvcmVpaXdRT0R2 8 | bXg2d1BDK2FRRGtNK2dXUkplM2JvbUtDTUkwZzZCZXJ6bVVIVHRKMVdpeTlLNGgx 9 | TU11cWZteklHY1Q4bkw1Q01qSmZwdHIvRlpzNXpnM3YzeWpQSEQ3V1hENnAxUS9h 10 | RVNUNEI0K2UwUFhyZDJBajAwWEUrUGwyNEE9PSJ9 11 | -----END ENCRYPTED SIGSTORE PRIVATE KEY----- 12 | -------------------------------------------------------------------------------- /pkg/flog/level_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Level"; DO NOT EDIT. 2 | 3 | package flog 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[Debug-0] 12 | _ = x[Panic-1] 13 | } 14 | 15 | const _Level_name = "DebugPanic" 16 | 17 | var _Level_index = [...]uint8{0, 5, 10} 18 | 19 | func (i Level) String() string { 20 | idx := int(i) - 0 21 | if i < 0 || idx >= len(_Level_index)-1 { 22 | return "Level(" + strconv.FormatInt(int64(i), 10) + ")" 23 | } 24 | return _Level_name[_Level_index[idx]:_Level_index[idx+1]] 25 | } 26 | -------------------------------------------------------------------------------- /contrib/packaging/config/finch.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=finch daemon 3 | Documentation=https://runfinch.com 4 | After=network.target local-fs.target containerd.service finch.socket 5 | Wants=network.target containerd.service 6 | Requires=finch.socket 7 | 8 | [Service] 9 | ExecStart=/bin/sh -c 'PATH="/usr/libexec/finch:/usr/libexec/finch/cni/bin/:$PATH" exec /usr/libexec/finch/finch-daemon --debug --config-file /etc/finch/nerdctl/nerdctl.toml --socket-addr fd://' 10 | Type=notify 11 | Delegate=yes 12 | Restart=always 13 | RestartSec=5 14 | Environment=BUILDKIT_HOST=unix:///var/lib/finch/buildkit/buildkitd.sock 15 | Environment=NERDCTL_TOML=/etc/finch/nerdctl/nerdctl.toml 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | -------------------------------------------------------------------------------- /installer-builder/templates/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleName 6 | Finch 7 | CFBundleDisplayName 8 | Finch 9 | CFBundleIdentifier 10 | org.Finch 11 | CFBundleVersion 12 | __VERSION__ 13 | CFBundlePackageType 14 | APPL 15 | CFBundleExecutable 16 | Finch 17 | CFBundleIconFile 18 | Finch.icns 19 | 20 | -------------------------------------------------------------------------------- /benchmark/container/container_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package container runs benchmark tests related to container development of Finch. 5 | package container 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/runfinch/finch/benchmark" 11 | ) 12 | 13 | func BenchmarkContainer(b *testing.B) { 14 | suite := &benchmark.Suite{} 15 | err := suite.Setup() 16 | if err != nil { 17 | b.Fatal(err) 18 | } 19 | 20 | b.Run("BenchmarkContainerRun", func(b *testing.B) { 21 | suite.BenchmarkContainerRun(b) 22 | }) 23 | 24 | b.Run("BenchmarkImageBuild", func(b *testing.B) { 25 | suite.BenchmarkImageBuild(b) 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /cmd/finch/support_bundle_remote.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/runfinch/finch/pkg/lima" 12 | ) 13 | 14 | func (gsa *generateSupportBundleAction) canCreateBundle() error { 15 | status, err := lima.GetVMStatus(gsa.ncc, gsa.logger, limaInstanceName) 16 | if err != nil { 17 | return err 18 | } 19 | switch status { 20 | case lima.Nonexistent: 21 | return fmt.Errorf("cannot create support bundle for nonexistent VM, run `finch %s init` to create a new instance", 22 | virtualMachineRootCmd) 23 | default: 24 | return nil 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pkg/config/defaults_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package config 7 | 8 | import ( 9 | "github.com/xorcare/pointer" 10 | 11 | "github.com/runfinch/finch/pkg/command" 12 | "github.com/runfinch/finch/pkg/fmemory" 13 | ) 14 | 15 | func vmDefault(cfg *Finch) { 16 | if cfg.VMType == nil { 17 | cfg.VMType = pointer.String("wsl2") 18 | } 19 | } 20 | 21 | // applyDefaults sets default configuration options if they are not already set. 22 | func applyDefaults( 23 | cfg *Finch, 24 | _ LoadSystemDeps, 25 | _ fmemory.Memory, 26 | _ command.Creator, 27 | ) *Finch { 28 | vmDefault(cfg) 29 | return cfg 30 | } 31 | -------------------------------------------------------------------------------- /docs/cmd/finch_vm_disk.md: -------------------------------------------------------------------------------- 1 | # finch vm disk 2 | 3 | Manage virtual machine disk operations. 4 | 5 | > **Note:** These commands are currently supported on macOS only. Not available on Windows. 6 | 7 | --- 8 | 9 | ## Commands 10 | 11 | ## disk info 12 | 13 | Display information about the virtual machine disk. 14 | 15 | ```bash 16 | finch vm disk info [flags] 17 | ``` 18 | 19 | ### Options 20 | 21 | ```text 22 | -h, --help help for disk info 23 | ``` 24 | 25 | ## disk resize 26 | 27 | Display information about the virtual machine disk. 28 | 29 | ```bash 30 | finch vm disk resize --size [flags] 31 | ``` 32 | 33 | ### Options 34 | 35 | ```text 36 | -h, --help help for disk resize 37 | --size string New size for the disk (e.g., 60GiB) (required) 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/cmd/finch_exec.md: -------------------------------------------------------------------------------- 1 | # finch exec 2 | 3 | Run a command in a running container 4 | 5 | ```text 6 | finch exec [flags] CONTAINER COMMAND [ARG...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -d, --detach Detached mode: run command in the background 13 | -e, --env stringArray Set environment variables 14 | --env-file strings Set environment variables from file 15 | -h, --help help for exec 16 | -i, --interactive Keep STDIN open even if not attached 17 | --privileged Give extended privileges to the command 18 | -t, --tty Allocate a pseudo-TTY 19 | -u, --user string Username or UID (format: [:]) 20 | -w, --workdir string Working directory inside the container 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/cmd/finch_ps.md: -------------------------------------------------------------------------------- 1 | # finch ps 2 | 3 | List containers 4 | 5 | ```text 6 | finch ps [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | -a, --all Show all containers (default shows just running) 13 | -f, --filter strings Filter matches containers based on given conditions 14 | --format string Format the output using the given Go template, e.g, '{{json .}}', 'wide' 15 | -h, --help help for ps 16 | -n, --last int Show n last created containers (includes all states) (default -1) 17 | -l, --latest Show the latest created container (includes all states) 18 | --no-trunc Don't truncate output 19 | -q, --quiet Only display container IDs 20 | -s, --size Display total file sizes 21 | ``` 22 | -------------------------------------------------------------------------------- /contrib/packaging/deb/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Clean up configuration files and data directories if purging 5 | if [ "$1" = "purge" ]; then 6 | # Remove configuration files 7 | rm -rf /etc/finch 8 | 9 | # Remove data directories 10 | rm -rf /var/lib/finch 11 | rm -rf /usr/libexec/finch 12 | 13 | # Remove systemd service files 14 | rm -f /etc/systemd/system/finch.service 15 | rm -f /etc/systemd/system/finch.socket 16 | rm -f /etc/systemd/system/finch-buildkit.service 17 | rm -f /etc/systemd/system/finch-buildkit.socket 18 | rm -f /etc/systemd/system/finch-soci.service 19 | rm -f /etc/systemd/system/finch-soci.socket 20 | 21 | # Reload systemd to recognize the removed services 22 | systemctl daemon-reload || true 23 | fi 24 | 25 | exit 0 26 | -------------------------------------------------------------------------------- /pkg/flog/formatter_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Formatter"; DO NOT EDIT. 2 | 3 | package flog 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[Text-0] 12 | _ = x[TextWithoutTruncation-1] 13 | _ = x[JSON-2] 14 | } 15 | 16 | const _Formatter_name = "TextTextWithoutTruncationJSON" 17 | 18 | var _Formatter_index = [...]uint8{0, 4, 25, 29} 19 | 20 | func (i Formatter) String() string { 21 | idx := int(i) - 0 22 | if i < 0 || idx >= len(_Formatter_index)-1 { 23 | return "Formatter(" + strconv.FormatInt(int64(i), 10) + ")" 24 | } 25 | return _Formatter_name[_Formatter_index[idx]:_Formatter_index[idx+1]] 26 | } 27 | -------------------------------------------------------------------------------- /installer-builder/templates/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-jit 6 | 7 | com.apple.security.cs.allow-unsigned-executable-memory 8 | 9 | com.apple.security.cs.disable-library-validation 10 | 11 | com.apple.security.hypervisor 12 | 13 | com.apple.security.inherit 14 | 15 | com.apple.security.virtualization 16 | 17 | com.apple.security.network.server 18 | 19 | com.apple.security.network.client 20 | 21 | 22 | -------------------------------------------------------------------------------- /pkg/config/config_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package config 7 | 8 | import ( 9 | "github.com/runfinch/finch/pkg/command" 10 | ) 11 | 12 | // SystemSettings represents the system configuration specifc to Windows. 13 | type SystemSettings struct { 14 | SharedSystemSettings `yaml:",inline"` 15 | } 16 | 17 | // Finch represents the configuration file for Finch CLI. 18 | type Finch struct { 19 | SystemSettings `yaml:",inline"` 20 | SharedSettings `yaml:",inline"` 21 | } 22 | 23 | // SupportsWSL2 checks if system supports WSL2 and sets default version to 2. 24 | func SupportsWSL2(cmdCreator command.Creator) error { 25 | return cmdCreator.Create("wsl", "--set-default-version", "2").Run() 26 | } 27 | -------------------------------------------------------------------------------- /e2e/vm/vm_linux_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | // Package vm runs tests related to the virtual machine. 7 | package vm 8 | 9 | import ( 10 | "testing" 11 | 12 | "github.com/onsi/ginkgo/v2" 13 | "github.com/onsi/gomega" 14 | 15 | "github.com/runfinch/finch/e2e" 16 | ) 17 | 18 | //nolint:paralleltest // TestVM is like TestMain for the VM-related tests. 19 | func TestVM(t *testing.T) { 20 | const description = "Finch Virtual Machine E2E Tests" 21 | 22 | o, err := e2e.CreateOption() 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | 27 | ginkgo.Describe("", func() { 28 | testSupportBundle(o) 29 | }) 30 | 31 | gomega.RegisterFailHandler(ginkgo.Fail) 32 | ginkgo.RunSpecs(t, description) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/dependency/credhelper/cred_helper_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package credhelper 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | 12 | "github.com/runfinch/finch/pkg/dependency" 13 | ) 14 | 15 | func Test_NewDependencyGroup(t *testing.T) { 16 | t.Parallel() 17 | 18 | want := dependency.NewGroup(newDeps(nil, nil, "", nil, nil, "", ""), description, errMsg) 19 | got := NewDependencyGroup(nil, nil, "", nil, nil, "", "") 20 | assert.Equal(t, want, got) 21 | } 22 | 23 | func Test_newDeps(t *testing.T) { 24 | t.Parallel() 25 | 26 | got := newDeps(nil, nil, "", nil, nil, "", "") 27 | require.Equal(t, 1, len(got)) 28 | assert.IsType(t, nil, got[0]) 29 | } 30 | -------------------------------------------------------------------------------- /pkg/path/finch.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package path contains functions to find/calculate path used in the project. 5 | package path 6 | 7 | import "github.com/runfinch/finch/pkg/system" 8 | 9 | // Finch provides a set of methods that calculate paths relative to the Finch path. 10 | type Finch string 11 | 12 | // FinchFinderDeps provides all the dependencies FindFinch needs to find Finch. 13 | // 14 | //go:generate mockgen -copyright_file=../../copyright_header -destination=../mocks/finch_finder_deps.go -package=mocks -mock_names FinchFinderDeps=FinchFinderDeps . FinchFinderDeps 15 | type FinchFinderDeps interface { 16 | system.SymlinksEvaluator 17 | system.ExecutableFinder 18 | system.FilePathJoiner 19 | system.EnvGetter 20 | system.UserHomeDir 21 | } 22 | -------------------------------------------------------------------------------- /scripts/gen-code-windows.ps1: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # gen-code-windows.ps1 5 | 6 | # existing logic for codegen installs codegen tools locally 7 | # to "tools_bin" and prepends $PATH with "tools_bin". This syntax to 8 | # specify a PATH= before command in Windows Make / git-bash is broken; 9 | # this script is a workaround to perform the codegen. 10 | 11 | # tools_bin is created in root of finch project. 12 | $GOBIN = Join-Path $PSScriptRoot "../tools_bin" 13 | $env:GOBIN=$GOBIN 14 | 15 | # Install the required Go tools specifying GOBIN 16 | go install go.uber.org/mock/mockgen 17 | go install golang.org/x/tools/cmd/stringer 18 | 19 | # Update the PATH environment variable and then run 'go generate' 20 | $env:PATH = "${GOBIN};${env:PATH}" 21 | go generate ./... . 22 | -------------------------------------------------------------------------------- /pkg/fmemory/fmemory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package fmemory provides functions and methods to get memory information about the current system. 5 | package fmemory 6 | 7 | import ( 8 | "github.com/pbnjay/memory" 9 | ) 10 | 11 | // Memory abstracts out memory.TotalMemory to facilitate unit testing. 12 | // 13 | //go:generate mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_fmemory_memory.go -package=mocks -mock_names Memory=Memory . Memory 14 | type Memory interface { 15 | TotalMemory() uint64 16 | } 17 | 18 | type mem struct{} 19 | 20 | func (mem) TotalMemory() uint64 { 21 | return memory.TotalMemory() 22 | } 23 | 24 | // NewMemory returns a Memory instance that calls memory.TotalMemory under the hood. 25 | func NewMemory() Memory { 26 | return &mem{} 27 | } 28 | -------------------------------------------------------------------------------- /pkg/dependency/vmnet/vmnet_unix_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package vmnet 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | 14 | "github.com/runfinch/finch/pkg/dependency" 15 | ) 16 | 17 | func Test_NewDependencyGroup(t *testing.T) { 18 | t.Parallel() 19 | 20 | want := dependency.NewGroup(newDeps(nil, nil, nil, "", nil), description, errMsg) 21 | got := NewDependencyGroup(nil, nil, nil, "", nil) 22 | assert.Equal(t, want, got) 23 | } 24 | 25 | func Test_newDeps(t *testing.T) { 26 | t.Parallel() 27 | 28 | got := newDeps(nil, nil, nil, "", nil) 29 | require.Equal(t, 3, len(got)) 30 | assert.IsType(t, (*binaries)(nil), got[0]) 31 | assert.IsType(t, (*sudoersFile)(nil), got[1]) 32 | } 33 | -------------------------------------------------------------------------------- /msi-builder/README.md: -------------------------------------------------------------------------------- 1 | # FinchWindowsMSI 2 | 3 | Finch Windows MSI Tool to generate MSI installer from Finch build 4 | 5 | ## Instructions 6 | 7 | [1] Build finch: `make FINCH_OS_IMAGE_LOCATION_ROOT=__INSTALLFOLDER__` 8 | 9 | - It will inject the placeholder `__INSTALLFOLDER__` into `os\finch.yaml` for the rootfs location 10 | 11 | [2] Run the following command to generate the MSI installer: 12 | `.\BuildFinchMSI.ps1 -SourcePath "" -Version ` 13 | 14 | **Parameters:** 15 | 16 | - SourcePath: Refers to the finch build `_output` folder, e.g., `C:\Users\\Repo\finch\_output\.` It's an optional parameter. If not provided, the default path is finch's _output folder. (You need to build finch before running the MSI tool). 17 | 18 | - Version: A required parameter that should match the version format, e.g., `0.10.2`. 19 | 20 | [3] The `Finch-.msi` will be generated to the `msi-builder\build` folder 21 | -------------------------------------------------------------------------------- /pkg/support/config.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package support 5 | 6 | import ( 7 | fpath "github.com/runfinch/finch/pkg/path" 8 | ) 9 | 10 | type bundleConfig struct { 11 | finch fpath.Finch 12 | rootDir string 13 | } 14 | 15 | // BundleConfig provides methods that configure what is included in a support bundle. 16 | // 17 | //go:generate mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_support_config.go -package=mocks -mock_names BundleConfig=BundleConfig . BundleConfig 18 | type BundleConfig interface { 19 | LogFiles() []string 20 | ConfigFiles() []string 21 | JournalServices() []string 22 | } 23 | 24 | // NewBundleConfig creates a new bundleConfig. 25 | func NewBundleConfig(finch fpath.Finch, rootDir string) BundleConfig { 26 | return &bundleConfig{ 27 | finch: finch, 28 | rootDir: rootDir, 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/cmd/finch_support-bundle_generate.md: -------------------------------------------------------------------------------- 1 | # finch support-bundle generate 2 | 3 | Generates a collection of logs and configs that can be uploaded to a Github issue to help debug issues. 4 | 5 | ```text 6 | finch support-bundle generate [flags] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --exclude stringArray files to exclude from the support bundle. If you specify a base name, all files matching that base name will be excluded. If you specify an absolute or relative path, only exact matches will be excluded. To exclude journal logs for a service, prefix the file path with "service":. To exclude all journal logs, use "service:all" 13 | -h, --help help for generate 14 | --include stringArray additional files to include in the support bundle, specified by absolute or relative path. To include journal logs for a service, prefix the file path with "service:". To include a file from the VM, prefix the file path with "vm:" 15 | ``` 16 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | commit-message: 8 | # When a dependency is updated, 9 | # we want release-please to treat the corresponding commit as a releasable unit 10 | # because it may contain a security fix. 11 | # 12 | # Re. how that is achieved, see `changelog-types` in workflows/release-please.yml. 13 | prefix: "build" 14 | include: "scope" 15 | groups: 16 | docker: 17 | patterns: 18 | - "github.com/docker/docker" 19 | - "github.com/docker/cli" 20 | project-dependency: 21 | exclude-patterns: 22 | - "github.com/containerd/nerdctl/v2" 23 | - "github.com/docker/docker" 24 | - "github.com/docker/cli" 25 | - package-ecosystem: "github-actions" 26 | directory: "/" 27 | schedule: 28 | interval: "daily" 29 | commit-message: 30 | prefix: "ci" 31 | include: "scope" 32 | -------------------------------------------------------------------------------- /installer-builder/tools/merge-back-signed-executables.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit 3 | set -o pipefail 4 | 5 | mergeBackSignedExecutables() { 6 | for file in $(ls -a ./installer-builder/output/executables/signed/Payload/EXECUTABLES_TO_SIGN) 7 | do 8 | if [[ $file != '.' && $file != '..' ]] 9 | then 10 | #recover the original long file path and place the signed executables back 11 | #replace '__' to original '/' 12 | #e.g., the file name is 'b__c' and ./a is the root: 13 | #1) ./a will be appended as prefix 14 | #2) '__' will be replaced by '/' 15 | #3) final executable path is './a/b/c' 16 | originalPath=${file//__/\/} 17 | fullPath=./installer-builder/output/origin/_output/$originalPath 18 | cp -f ./installer-builder/output/executables/signed/Payload/EXECUTABLES_TO_SIGN/"$file" "$fullPath" 19 | fi 20 | done 21 | } 22 | 23 | mergeBackSignedExecutables -------------------------------------------------------------------------------- /cmd/finch/version_native.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | ) 12 | 13 | func (va *versionAction) printVersion(format string) error { 14 | nerdctlArgs := []string{"version", "--format", "json"} 15 | out, err := va.creator.CreateWithoutStdio(nerdctlArgs...).Output() 16 | if err != nil { 17 | return fmt.Errorf("failed to create the nerdctl version command: %w", err) 18 | } 19 | 20 | var nerdctlVersion NerdctlVersionOutput 21 | err = json.Unmarshal(out, &nerdctlVersion) 22 | if err != nil { 23 | return fmt.Errorf("failed to JSON-unmarshal the nerdctl version output: %w", err) 24 | } 25 | 26 | tmpl, err := newVersionTemplate(format) 27 | if err != nil { 28 | return err 29 | } 30 | err = va.showVersionMessage(tmpl, nerdctlVersion) 31 | if err != nil { 32 | return err 33 | } 34 | 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /pkg/support/config_remote.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package support 7 | 8 | import ( 9 | "path" 10 | "path/filepath" 11 | "runtime" 12 | ) 13 | 14 | func (bc *bundleConfig) LogFiles() []string { 15 | files := []string{ 16 | filepath.Join(bc.finch.LimaInstancePath(), "ha.stderr.log"), 17 | filepath.Join(bc.finch.LimaInstancePath(), "ha.stdout.log"), 18 | } 19 | 20 | if runtime.GOOS != "windows" { 21 | files = append(files, filepath.Join(bc.finch.LimaInstancePath(), "serial.log")) 22 | } 23 | return files 24 | } 25 | 26 | func (bc *bundleConfig) ConfigFiles() []string { 27 | return []string{ 28 | path.Join(bc.finch.LimaInstancePath(), "lima.yaml"), 29 | bc.finch.ConfigFilePath(bc.rootDir), 30 | } 31 | } 32 | 33 | func (bc *bundleConfig) JournalServices() []string { 34 | return []string{"service:containerd", "service:finch", "service:buildkit", "service:soci"} 35 | } 36 | -------------------------------------------------------------------------------- /pkg/lima/wrapper/lima_wrapper.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package wrapper provides an interface to wrap Lima utils 5 | package wrapper 6 | 7 | import ( 8 | "os/user" 9 | 10 | "github.com/lima-vm/lima/pkg/osutil" 11 | 12 | "github.com/runfinch/finch/pkg/lima" 13 | ) 14 | 15 | // LimaWrapper provides Lima utils in an interface to facilitate mocking 16 | // 17 | //go:generate mockgen --destination=../../mocks/lima_wrapper.go -package=mocks github.com/runfinch/finch/pkg/lima/wrapper LimaWrapper 18 | type LimaWrapper interface { 19 | LimaUser(warn bool) *user.User 20 | } 21 | 22 | type limaWrapper struct{} 23 | 24 | // NewLimaWrapper returns a new LimaWrapper. 25 | func NewLimaWrapper() LimaWrapper { 26 | return &limaWrapper{} 27 | } 28 | 29 | // LimaUser returns the user that will be used inside the Lima VM. 30 | func (*limaWrapper) LimaUser(warn bool) *user.User { 31 | return osutil.LimaUser(lima.LimaVersion, warn) 32 | } 33 | -------------------------------------------------------------------------------- /pkg/templates/templates.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package templates provides functionality for working with templates, 5 | // including JSON formatting for output. 6 | package templates 7 | 8 | import ( 9 | "bytes" 10 | "encoding/json" 11 | "strings" 12 | "text/template" 13 | ) 14 | 15 | // Key and format strings in the --format option. 16 | const ( 17 | JSONFormatKey = "json" 18 | JSONFormat = "{{json .}}" 19 | ) 20 | 21 | var basicFunctions = template.FuncMap{ 22 | "json": func(v any) string { 23 | buf := &bytes.Buffer{} 24 | 25 | enc := json.NewEncoder(buf) 26 | enc.SetEscapeHTML(false) 27 | err := enc.Encode(v) 28 | if err != nil { 29 | panic(err) 30 | } 31 | 32 | return strings.TrimSpace(buf.String()) 33 | }, 34 | } 35 | 36 | // New creates a new empty template with the provided tag and built-in template functions. 37 | func New(tag string) *template.Template { 38 | return template.New(tag).Funcs(basicFunctions) 39 | } 40 | -------------------------------------------------------------------------------- /pkg/lima/wrapper/lima_wrapper_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package wrapper 5 | 6 | import ( 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestNewLimaWrapper(t *testing.T) { 13 | t.Parallel() 14 | testCases := []struct { 15 | name string 16 | }{ 17 | { 18 | name: "Test NewLimaWrapper happy path", 19 | }, 20 | } 21 | 22 | for _, tc := range testCases { 23 | t.Run(tc.name, func(t *testing.T) { 24 | t.Parallel() 25 | got := NewLimaWrapper() 26 | assert.NotNil(t, got) 27 | }) 28 | } 29 | } 30 | 31 | func TestLimaWrapper_LimaUser(t *testing.T) { 32 | t.Parallel() 33 | testCases := []struct { 34 | name string 35 | }{ 36 | { 37 | name: "Test NewLimaWrapper happy path", 38 | }, 39 | } 40 | 41 | for _, tc := range testCases { 42 | t.Run(tc.name, func(t *testing.T) { 43 | t.Parallel() 44 | lw := NewLimaWrapper() 45 | assert.NotNil(t, lw.LimaUser(false)) 46 | }) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.github/workflows/canary-deb.yaml: -------------------------------------------------------------------------------- 1 | name: Deb Canary 2 | 3 | on: 4 | # This workflow will run from the release-automation.yaml automation on each merge 5 | workflow_dispatch: 6 | inputs: 7 | ref_name: 8 | required: true 9 | type: string 10 | workflow_call: 11 | inputs: 12 | ref_name: 13 | required: true 14 | type: string 15 | 16 | # This workflow will run every 5 min 17 | schedule: 18 | - cron: '*/10 * * * *' 19 | 20 | # This workflow will run when the workflow file is updated 21 | pull_request: 22 | paths: 23 | - '.github/workflows/canary-deb.yaml' 24 | - 'scripts/canary-deb.sh' 25 | 26 | jobs: 27 | canary-deb: 28 | name: Test Finch APT repo health 29 | runs-on: ubuntu-latest 30 | timeout-minutes: 2 31 | steps: 32 | - name: Checkout canary script 33 | uses: actions/checkout@v5 34 | with: 35 | sparse-checkout: | 36 | scripts/canary-deb.sh 37 | - name: Run canary script 38 | run: ./scripts/canary-deb.sh 39 | -------------------------------------------------------------------------------- /pkg/command/exit_error.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package command 5 | 6 | import ( 7 | "errors" 8 | "fmt" 9 | "os/exec" 10 | ) 11 | 12 | type exitError struct { 13 | wrapped *exec.ExitError 14 | } 15 | 16 | func newExitError(wrapped *exec.ExitError) *exitError { 17 | return &exitError{wrapped: wrapped} 18 | } 19 | 20 | // wrapIfExitError makes the returned error's Error() print stderr along with the exit code if err is of type *exec.ExitError. 21 | // That's useful because *exec.ExitError by default only prints the exit code, while stderr is usually needed to help debug. 22 | func wrapIfExitError(err error) error { 23 | var exitErr *exec.ExitError 24 | if !errors.As(err, &exitErr) { 25 | return err 26 | } 27 | return newExitError(exitErr) 28 | } 29 | 30 | func (e *exitError) Error() string { 31 | return fmt.Sprintf("%s, stderr: %s", e.wrapped.Error(), e.wrapped.Stderr) 32 | } 33 | 34 | func (e *exitError) Unwrap() error { 35 | return e.wrapped 36 | } 37 | -------------------------------------------------------------------------------- /pkg/winutil/io.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package winutil provides provides utility functions to run commands with 5 | // elevated Administrator privileges. 6 | package winutil 7 | 8 | import ( 9 | "io" 10 | 11 | "golang.org/x/text/encoding/unicode" 12 | "golang.org/x/text/transform" 13 | ) 14 | 15 | // FromUTF16le returns an io.Reader for UTF16le data. 16 | // Windows uses little endian by default, use unicode.UseBOM policy to retrieve BOM from the text, 17 | // and unicode.LittleEndian as a fallback. 18 | func FromUTF16le(r io.Reader) io.Reader { 19 | o := transform.NewReader(r, unicode.UTF16(unicode.LittleEndian, unicode.UseBOM).NewDecoder()) 20 | return o 21 | } 22 | 23 | // FromUTF16leToString reads from Unicode 16 LE encoded data from an io.Reader and returns a string. 24 | func FromUTF16leToString(r io.Reader) (string, error) { 25 | out, err := io.ReadAll(FromUTF16le(r)) 26 | if err != nil { 27 | return "", err 28 | } 29 | 30 | return string(out), nil 31 | } 32 | -------------------------------------------------------------------------------- /pkg/path/finch_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package path 7 | 8 | import ( 9 | "fmt" 10 | "strings" 11 | 12 | "golang.org/x/sys/windows/registry" 13 | ) 14 | 15 | // FinchRootDir returns the path to the Finch root directory, which is %LOCALAPPDATA% on Windows. 16 | // It also canonicalizes any environment variables that may be unexpanded in the path so that all 17 | // paths based on it can be passed safely to other programs which may execute outside of the user's context. 18 | func (Finch) FinchRootDir(ffd FinchFinderDeps) (string, error) { 19 | appDir := ffd.Env("LOCALAPPDATA") 20 | expandedPath, err := registry.ExpandString(appDir) 21 | if err != nil { 22 | return "", err 23 | } 24 | // reject any paths that contain unexpected characters 25 | if strings.Contains(expandedPath, "&") || strings.Contains(expandedPath, `"`) { 26 | return "", fmt.Errorf("unexpected LOCALAPPDATA path %q", expandedPath) 27 | } 28 | 29 | return expandedPath, nil 30 | } 31 | -------------------------------------------------------------------------------- /docs/cmd/finch_image.md: -------------------------------------------------------------------------------- 1 | # finch image 2 | 3 | Manage images 4 | 5 | ```text 6 | finch image [flags] 7 | ``` 8 | 9 | ## Commands 10 | 11 | ```text 12 | build Build an image from a Dockerfile. Needs buildkitd to be running. 13 | convert convert an image 14 | decrypt decrypt an image 15 | encrypt encrypt image layers 16 | history Show the history of an image 17 | inspect Display detailed information on one or more images. 18 | load Load an image from a tar archive or STDIN 19 | ls List images 20 | prune Remove unused images 21 | pull Pull an image from a registry. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS. 22 | push Push an image or a repository to a registry. Optionally specify "ipfs://" or "ipns://" scheme to push image to IPFS. 23 | rm Remove one or more images 24 | save Save one or more images to a tar archive (streamed to STDOUT by default) 25 | tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE 26 | ``` 27 | 28 | ## Options 29 | 30 | ```text 31 | -h, --help help for image 32 | ``` 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report a bug to help improve Finch 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Please do not report security issues through this template.** Refer to [Security](https://github.com/runfinch/finch?tab=security-ov-file#reporting-security-issues) for the proper reporting channels. 11 | 12 | --- 13 | 14 | **Describe the bug** 15 | Briefly describe the problem you are having. 16 | 17 | 18 | **Steps to reproduce** 19 | A clear, step-by-step set of instructions to reproduce the bug. 20 | 21 | 22 | **Expected behavior** 23 | Description of what you expected to happen. 24 | 25 | 26 | **Screenshots or logs** 27 | If applicable, add screenshots or logs to help explain your problem. 28 | 29 | 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | 34 | 35 | _To help debug the issue as quickly as possible, we recommend generating a support bundle with `finch support-bundle generate` and attaching it to this issue. This packages all Finch-related configs and logs into one file._ -------------------------------------------------------------------------------- /networks.yaml: -------------------------------------------------------------------------------- 1 | # Paths to vde executables. Because vde_vmnet is invoked via sudo it should be 2 | # installed where only root can modify/replace it. This means also none of the 3 | # parent directories should be writable by the user. 4 | # 5 | # The varRun directory also must not be writable by the user because it will 6 | # include the vde_vmnet pid files. Those will be terminated via sudo, so replacing 7 | # the pid files would allow killing of arbitrary privileged processes. varRun 8 | # however MUST be writable by the daemon user. 9 | # 10 | # None of the paths segments may be symlinks, why it has to be /private/var 11 | # instead of /var etc. 12 | paths: 13 | socketVMNet: /opt/finch/bin/socket_vmnet 14 | varRun: /private/var/run/finch-lima 15 | sudoers: /private/etc/sudoers.d/finch-lima 16 | 17 | group: everyone 18 | 19 | networks: 20 | finch-shared: 21 | mode: shared 22 | gateway: 192.168.105.1 23 | dhcpEnd: 192.168.105.254 24 | netmask: 255.255.255.0 25 | host: 26 | mode: host 27 | gateway: 192.168.106.1 28 | dhcpEnd: 192.168.106.254 29 | netmask: 255.255.255.0 30 | -------------------------------------------------------------------------------- /benchmark/all/all_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package all runs all the benchmark tests of Finch. 5 | package all 6 | 7 | import ( 8 | "testing" 9 | 10 | "github.com/runfinch/finch/benchmark" 11 | ) 12 | 13 | func BenchmarkAll(b *testing.B) { 14 | suite := &benchmark.Suite{} 15 | err := suite.Setup() 16 | if err != nil { 17 | b.Fatal(err) 18 | } 19 | 20 | b.Run("BenchmarkVMInit", func(b *testing.B) { 21 | suite.BenchmarkVMInit(b) 22 | }) 23 | 24 | b.Run("BenchmarkVMStart", func(b *testing.B) { 25 | suite.BenchmarkVMStart(b) 26 | }) 27 | 28 | err = suite.InitVM() 29 | if err != nil { 30 | b.Fatal(err) 31 | } 32 | 33 | b.Run("BenchmarkContainerRun", func(b *testing.B) { 34 | suite.BenchmarkContainerRun(b) 35 | }) 36 | 37 | b.Run("BenchmarkImageBuild", func(b *testing.B) { 38 | suite.BenchmarkImageBuild(b) 39 | }) 40 | 41 | err = suite.StopVM() 42 | if err != nil { 43 | b.Fatal(err) 44 | } 45 | err = suite.RemoveVM() 46 | if err != nil { 47 | b.Fatal(err) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /pkg/config/defaults_windows_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package config 7 | 8 | import ( 9 | "github.com/xorcare/pointer" 10 | "go.uber.org/mock/gomock" 11 | 12 | "github.com/runfinch/finch/pkg/mocks" 13 | ) 14 | 15 | func applyDefaultPlatformSpecificTestCases() applyDefaultTestCases { 16 | return []struct { 17 | name string 18 | cfg *Finch 19 | mockSvc func( 20 | deps *mocks.LoadSystemDeps, 21 | mem *mocks.Memory, 22 | ecc *mocks.CommandCreator, 23 | ctrl *gomock.Controller, 24 | ) 25 | want *Finch 26 | }{ 27 | { 28 | name: "happy path", 29 | cfg: &Finch{}, 30 | mockSvc: func( 31 | _ *mocks.LoadSystemDeps, 32 | _ *mocks.Memory, 33 | _ *mocks.CommandCreator, 34 | _ *gomock.Controller, 35 | ) { 36 | }, 37 | want: &Finch{ 38 | SystemSettings: SystemSettings{ 39 | SharedSystemSettings: SharedSystemSettings{ 40 | VMType: pointer.String("wsl2"), 41 | }, 42 | }, 43 | }, 44 | }, 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /cmd/finch/main_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package main 7 | 8 | import ( 9 | "github.com/spf13/afero" 10 | 11 | "github.com/runfinch/finch/pkg/command" 12 | "github.com/runfinch/finch/pkg/config" 13 | "github.com/runfinch/finch/pkg/dependency" 14 | "github.com/runfinch/finch/pkg/dependency/credhelper" 15 | "github.com/runfinch/finch/pkg/dependency/vmnet" 16 | "github.com/runfinch/finch/pkg/flog" 17 | "github.com/runfinch/finch/pkg/path" 18 | "github.com/runfinch/finch/pkg/system" 19 | ) 20 | 21 | func dependencies( 22 | ecc command.Creator, 23 | fc *config.Finch, 24 | fp path.Finch, 25 | fs afero.Fs, 26 | ncc command.NerdctlCmdCreator, 27 | logger flog.Logger, 28 | finchRootPath string, 29 | ) []*dependency.Group { 30 | return []*dependency.Group{ 31 | credhelper.NewDependencyGroup( 32 | ecc, 33 | fs, 34 | fp, 35 | logger, 36 | fc, 37 | finchRootPath, 38 | system.NewStdLib().Arch(), 39 | ), 40 | vmnet.NewDependencyGroup(ecc, ncc, fs, fp, logger), 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cmd/finch/main_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | //go:generate go-winres make --file-version=git-tag --product-version=git-tag --arch amd64 --in ../../winres/winres.json 7 | 8 | package main 9 | 10 | import ( 11 | "github.com/spf13/afero" 12 | 13 | "github.com/runfinch/finch/pkg/command" 14 | "github.com/runfinch/finch/pkg/config" 15 | "github.com/runfinch/finch/pkg/dependency" 16 | "github.com/runfinch/finch/pkg/dependency/credhelper" 17 | "github.com/runfinch/finch/pkg/flog" 18 | "github.com/runfinch/finch/pkg/path" 19 | "github.com/runfinch/finch/pkg/system" 20 | ) 21 | 22 | func dependencies( 23 | ecc command.Creator, 24 | fc *config.Finch, 25 | fp path.Finch, 26 | fs afero.Fs, 27 | _ command.NerdctlCmdCreator, 28 | logger flog.Logger, 29 | finchDir string, 30 | ) []*dependency.Group { 31 | return []*dependency.Group{ 32 | credhelper.NewDependencyGroup( 33 | ecc, 34 | fs, 35 | fp, 36 | logger, 37 | fc, 38 | finchDir, 39 | system.NewStdLib().Arch(), 40 | ), 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /docs/cmd/finch_images.md: -------------------------------------------------------------------------------- 1 | # finch images 2 | 3 | List images 4 | 5 | ## Properties 6 | 7 | - REPOSITORY: Repository 8 | - TAG: Tag 9 | - NAME: Name of the image, --names for skip parsing as repository and tag. 10 | - IMAGE ID: OCI Digest. Usually different from Docker image ID. Shared for multi-platform images. 11 | - CREATED: Created time 12 | - PLATFORM: Platform 13 | - SIZE: Size of the unpacked snapshots 14 | - BLOB SIZE: Size of the blobs (such as layer tarballs) in the content store 15 | 16 | ```text 17 | finch images [flags] [REPOSITORY[:TAG]] 18 | ``` 19 | 20 | ## Options 21 | 22 | ```text 23 | -a, --all (unimplemented yet, always true) (default true) 24 | --digests Show digests (compatible with Docker, unlike ID) 25 | -f, --filter strings Filter output based on conditions provided 26 | --format string Format the output using the given Go template, e.g, '{{json .}}', 'wide' 27 | -h, --help help for images 28 | --names Show image names 29 | --no-trunc Don't truncate output 30 | -q, --quiet Only show numeric IDs 31 | ``` 32 | -------------------------------------------------------------------------------- /e2e/vm/vm_util_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package vm 7 | 8 | import ( 9 | "os" 10 | "os/exec" 11 | "path/filepath" 12 | 13 | "github.com/runfinch/common-tests/option" 14 | ) 15 | 16 | func limaCtlOpt(installed bool) (*option.Option, error) { 17 | var limactlPath, limaHomePathEnv string 18 | if installed { 19 | fpath, err := exec.LookPath("finch") 20 | if err != nil { 21 | return nil, err 22 | } 23 | realFinchPath, err := filepath.EvalSymlinks(fpath) 24 | if err != nil { 25 | return nil, err 26 | } 27 | limactlPath = filepath.Join(realFinchPath, "../../lima/bin/limactl") 28 | limaHomePathEnv = "LIMA_HOME=" + filepath.Join(realFinchPath, "../../lima/data") 29 | } else { 30 | wd, err := os.Getwd() 31 | if err != nil { 32 | return nil, err 33 | } 34 | limactlPath = filepath.Join(wd, "../../_output/lima/bin/limactl") 35 | limaHomePathEnv = "LIMA_HOME=" + filepath.Join(wd, "../../_output/lima/data") 36 | } 37 | return option.New([]string{limactlPath}, option.Env([]string{limaHomePathEnv})) 38 | } 39 | -------------------------------------------------------------------------------- /scripts/cleanup_wsl.ps1: -------------------------------------------------------------------------------- 1 | # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # We want these cleanup commands to always run, ignore errors so the step completes. 5 | $ErrorActionPreference = 'Ignore' 6 | 7 | taskkill /f /im wslservice.exe 2> nul || cmd /c "exit /b 0" 8 | sc query LxssManager | findstr "STATE" | findstr /C:"STOPPED" > nul && net start LxssManager 9 | wsl --list --verbose --all 10 | 11 | # Attempt to shut down WSL if any distribution is running 12 | if (wsl --list --verbose | findstr /C:"Running" > nul) { 13 | timeout 60s wsl --shutdown 14 | # Forcefully kill WSL if still running 15 | if (Get-Process -Name "wsl" -ErrorAction SilentlyContinue) { 16 | Stop-Process -Name "wsl" -Force 17 | } 18 | echo "WSL has been shut down successfully." 19 | } 20 | 21 | # Unregister 'lima-finch' distribution if it exists 22 | if (wsl --list --quiet | findstr /C:"lima-finch" > nul) { 23 | wsl --unregister lima-finch 24 | echo "'lima-finch' has been unregistered successfully." 25 | } 26 | 27 | wsl --list --verbose --all 28 | Remove-Item C:\Users\Administrator\AppData\Local\.finch -Recurse -------------------------------------------------------------------------------- /.github/workflows/release-please.yaml: -------------------------------------------------------------------------------- 1 | # When a third-party action is added (i.e., `uses`), please also add it to `download-licenses` in Makefile. 2 | on: 3 | push: 4 | branches: 5 | - main 6 | name: release-please 7 | 8 | permissions: 9 | contents: write # Required for trigger-release-automation job 10 | pull-requests: write 11 | 12 | jobs: 13 | release-please: 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | pull-requests: write 18 | timeout-minutes: 2 19 | outputs: 20 | release_created: ${{ steps.release.outputs.release_created }} 21 | steps: 22 | - uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0 23 | id: release 24 | trigger-release-automation: 25 | name: Trigger release-automation.yaml if PR is merged 26 | needs: [release-please] 27 | if: ${{ needs.release-please.outputs.release_created == 'true' }} 28 | permissions: 29 | contents: write # Required for uploading release assets 30 | id-token: write # Required for AWS OIDC authentication 31 | secrets: inherit # Pass all secrets to child workflows 32 | uses: ./.github/workflows/release-automation.yaml 33 | -------------------------------------------------------------------------------- /.github/workflows/lint-pr-title.yaml: -------------------------------------------------------------------------------- 1 | # When a third-party action is added (i.e., `uses`), please also add it to `download-licenses` in Makefile. 2 | name: "Lint PR Title" 3 | 4 | on: 5 | pull_request: 6 | types: 7 | - opened 8 | - edited 9 | - reopened 10 | - synchronize 11 | 12 | permissions: read-all 13 | 14 | jobs: 15 | main: 16 | name: conventional-commit 17 | runs-on: ubuntu-latest 18 | permissions: 19 | contents: read 20 | pull-requests: write 21 | timeout-minutes: 1 22 | steps: 23 | - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 24 | with: 25 | # List from https://github.com/commitizen/conventional-commit-types/blob/master/index.json 26 | # with custom types added at the end. 27 | # Custom types should also be added in release-please.yaml changelog-types. 28 | types: | 29 | feat 30 | fix 31 | docs 32 | style 33 | refactor 34 | perf 35 | test 36 | build 37 | ci 38 | chore 39 | revert 40 | exp 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | -------------------------------------------------------------------------------- /pkg/config/defaults_remote_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package config 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/stretchr/testify/require" 12 | "go.uber.org/mock/gomock" 13 | 14 | "github.com/runfinch/finch/pkg/mocks" 15 | ) 16 | 17 | type applyDefaultTestCases []struct { 18 | name string 19 | cfg *Finch 20 | mockSvc func( 21 | deps *mocks.LoadSystemDeps, 22 | mem *mocks.Memory, 23 | ecc *mocks.CommandCreator, 24 | ctrl *gomock.Controller, 25 | ) 26 | want *Finch 27 | } 28 | 29 | func Test_applyDefaults(t *testing.T) { 30 | t.Parallel() 31 | 32 | testCases := applyDefaultTestCases{} 33 | testCases = append(testCases, applyDefaultPlatformSpecificTestCases()...) 34 | 35 | for _, tc := range testCases { 36 | t.Run(tc.name, func(t *testing.T) { 37 | t.Parallel() 38 | 39 | ctrl := gomock.NewController(t) 40 | deps := mocks.NewLoadSystemDeps(ctrl) 41 | mem := mocks.NewMemory(ctrl) 42 | ecc := mocks.NewCommandCreator(ctrl) 43 | 44 | tc.mockSvc(deps, mem, ecc, ctrl) 45 | 46 | got := applyDefaults(tc.cfg, deps, mem, ecc) 47 | require.Equal(t, tc.want, got) 48 | }) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/config/lima_config_applier_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package config 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/lima-vm/lima/pkg/limayaml" 12 | "github.com/xorcare/pointer" 13 | ) 14 | 15 | func (lca *limaConfigApplier) configureVirtualizationFramework(limaCfg *limayaml.LimaYAML) (*limayaml.LimaYAML, error) { 16 | // Check if system supports wsl2 17 | 18 | if err := SupportsWSL2(lca.cmdCreator); err != nil { 19 | return nil, fmt.Errorf("wsl2 is not supported by your system %w", err) 20 | } 21 | if *lca.cfg.VMType == "wsl2" { 22 | limaCfg.MountType = pointer.String("wsl2") 23 | limaCfg.VMType = lca.cfg.VMType 24 | } else { 25 | return nil, fmt.Errorf("unsupported vm type \"%s\" for windows", *lca.cfg.VMType) 26 | } 27 | return limaCfg, nil 28 | } 29 | 30 | func (lca *limaConfigApplier) configureCPUs(limaCfg *limayaml.LimaYAML) *limayaml.LimaYAML { 31 | return limaCfg 32 | } 33 | 34 | func (lca *limaConfigApplier) configureMemory(limaCfg *limayaml.LimaYAML) *limayaml.LimaYAML { 35 | return limaCfg 36 | } 37 | 38 | func (lca *limaConfigApplier) configureMounts(limaCfg *limayaml.LimaYAML) *limayaml.LimaYAML { 39 | return limaCfg 40 | } 41 | -------------------------------------------------------------------------------- /msi-builder/postinstall.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | SET InstallDir=%~1 3 | SET FilePath=%InstallDir%\os\finch.yaml 4 | 5 | if exist "%FilePath%" ( 6 | powershell -Command "$installPath = '%InstallDir%'.Replace('\', '/'); $content = Get-Content '%FilePath%' -Raw; $content = $content -replace '__INSTALLFOLDER__', $installPath; $content = $content.Replace(\"`r`n\", \"`n\"); $utf8NoBom = New-Object System.Text.UTF8Encoding $false; [System.IO.File]::WriteAllText('%FilePath%', $content, $utf8NoBom)" 7 | ) 8 | 9 | icacls "%InstallDir%\lima\data" /grant Users:(OI)(CI)M 10 | 11 | :: Delete files and directories if they exist 12 | if exist "%InstallDir%\lima\data\finch\" rmdir /s /q "%InstallDir%\lima\data\finch\" 13 | if exist "%InstallDir%\lima\data\_config\override.yaml" del /f /q "%InstallDir%\lima\data\_config\override.yaml" 14 | if exist "%InstallDir%\lima\data\_config\default.yaml" del /f /q "%InstallDir%\lima\data\_config\default.yaml" 15 | if exist "%InstallDir%\lima\data\_config\user" del /f /q "%InstallDir%\lima\data\_config\user" 16 | if exist "%InstallDir%\lima\data\_config\user.pub" del /f /q "%InstallDir%\lima\data\_config\user.pub" 17 | if exist "%InstallDir%\lima\data\_networks\" rmdir /s /q "%InstallDir%\lima\data\_networks\" 18 | if exist "%InstallDir%\lima\data\_disks\" rmdir /s /q "%InstallDir%\lima\data\_disks\" 19 | -------------------------------------------------------------------------------- /pkg/command/exec_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package command 5 | 6 | import ( 7 | "bytes" 8 | "testing" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | var mockEnv = []string{"env=1"} 14 | 15 | func TestExecCommandCreator_Create(t *testing.T) { 16 | t.Parallel() 17 | 18 | got := NewExecCmdCreator().Create("") 19 | assert.IsType(t, got, &execCmd{}) 20 | } 21 | 22 | func TestExecCommand_SetEnv(t *testing.T) { 23 | t.Parallel() 24 | 25 | cmd := newExecCmd("") 26 | cmd.SetEnv(mockEnv) 27 | assert.Equal(t, cmd.Env, mockEnv) 28 | } 29 | 30 | func TestExecCommand_SetStdin(t *testing.T) { 31 | t.Parallel() 32 | 33 | cmd := newExecCmd("") 34 | buf := bytes.NewBuffer([]byte("test")) 35 | cmd.SetStdin(buf) 36 | assert.Equal(t, cmd.Stdin, buf) 37 | } 38 | 39 | func TestExecCommand_SetStdout(t *testing.T) { 40 | t.Parallel() 41 | 42 | cmd := newExecCmd("") 43 | buf := bytes.NewBuffer([]byte("test")) 44 | cmd.SetStdout(buf) 45 | assert.Equal(t, cmd.Stdout, buf) 46 | } 47 | 48 | func TestExecCommand_SetStderr(t *testing.T) { 49 | t.Parallel() 50 | 51 | cmd := newExecCmd("") 52 | buf := bytes.NewBuffer([]byte("test")) 53 | cmd.SetStderr(buf) 54 | assert.Equal(t, cmd.Stderr, buf) 55 | } 56 | -------------------------------------------------------------------------------- /scripts/clean-iptables.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to restore default iptables policies without keeping custom chains 3 | 4 | # Save current rules to a backup file with timestamp 5 | BACKUP_FILE="iptables-backup-$(date +%Y%m%d-%H%M%S).rules" 6 | echo "Creating backup of current rules to $BACKUP_FILE" 7 | iptables-save > "$BACKUP_FILE" 8 | 9 | echo "Current iptables rules before cleaning:" 10 | iptables -L -v -n --line-numbers 11 | 12 | # Flush all built-in chains 13 | echo "Flushing all built-in chains..." 14 | iptables -F INPUT 15 | iptables -F OUTPUT 16 | iptables -F FORWARD 17 | 18 | # Reset default policies for built-in chains 19 | echo "Setting default policies for built-in chains to ACCEPT..." 20 | iptables -P INPUT ACCEPT 21 | iptables -P OUTPUT ACCEPT 22 | iptables -P FORWARD ACCEPT 23 | 24 | # Flush all custom chains 25 | echo "Flushing and deleting all custom chains..." 26 | for chain in $(iptables -S | grep -E '^-N' | awk '{print $2}'); do 27 | echo "Flushing custom chain: $chain" 28 | iptables -F "$chain" || true 29 | echo "Deleting custom chain: $chain" 30 | iptables -X "$chain" || true 31 | done 32 | 33 | echo "Iptables rules after cleaning:" 34 | iptables -L -v -n --line-numbers 35 | 36 | echo "Iptables rules have been reset to default policies." 37 | echo "If you need to restore the original configuration, run: iptables-restore < $BACKUP_FILE" 38 | -------------------------------------------------------------------------------- /pkg/command/command.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package command invokes external commands. 5 | package command 6 | 7 | import "io" 8 | 9 | // Creator creates a Command. The semantics of the parameters are the same as those of exec.Command. 10 | // 11 | //go:generate mockgen -copyright_file=../../copyright_header -destination=../mocks/command_command_creator.go -package=mocks -mock_names Creator=CommandCreator . Creator 12 | type Creator interface { 13 | Create(name string, args ...string) Command 14 | } 15 | 16 | // Command contains 2 sets of methods. 17 | // The first set contains the methods to configure the command to be run (e.g., SetEnv). 18 | // The second set contains the methods to run the command (e.g., Output). 19 | // The semantics of the methods conform to that of the counterpart of exec.Cmd. 20 | // 21 | //go:generate mockgen -copyright_file=../../copyright_header -destination=../mocks/command_command.go -package=mocks -mock_names Command=Command . Command 22 | type Command interface { 23 | SetEnv([]string) 24 | SetStdin(io.Reader) 25 | SetStdout(io.Writer) 26 | SetStderr(io.Writer) 27 | StdinPipe() (io.WriteCloser, error) 28 | 29 | Run() error 30 | Start() error 31 | Wait() error 32 | Output() ([]byte, error) 33 | CombinedOutput() ([]byte, error) 34 | } 35 | -------------------------------------------------------------------------------- /e2e/vm/cred_helper_remote_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package vm 7 | 8 | import ( 9 | "fmt" 10 | "runtime" 11 | 12 | "github.com/onsi/ginkgo/v2" 13 | "github.com/onsi/gomega" 14 | "github.com/runfinch/common-tests/command" 15 | "github.com/runfinch/common-tests/option" 16 | ) 17 | 18 | var testCredHelper = func(o *option.Option, installed bool, registry string) { 19 | ginkgo.Describe("Credential Helper", func() { 20 | var vmType string 21 | 22 | ginkgo.BeforeEach(func() { 23 | if runtime.GOOS == "windows" { 24 | vmType = "wsl2" 25 | } else { 26 | vmType = "vz" 27 | } 28 | }) 29 | ginkgo.It("should pull from container registry", func() { 30 | if registry == "" { 31 | ginkgo.Skip("No Provided Container Registry Url") 32 | } 33 | resetVM(o) 34 | resetDisks(o, installed) 35 | writeFile(finchConfigFilePath, []byte(fmt.Sprintf("cpus: 6\nmemory: 4GiB\ncreds_helpers:\n "+ 36 | "- ecr-login\nvmType: %s\nrosetta: true", vmType))) 37 | command.New(o, virtualMachineRootCmd, "init").WithoutCheckingExitCode().WithTimeoutInSeconds(160).Run() 38 | command.New(o, "pull", registry).WithTimeoutInSeconds(600).Run() 39 | gomega.Expect(command.Stdout(o, "images", "-q", registry)).NotTo(gomega.BeEmpty()) 40 | }) 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /docs/cmd/finch_update.md: -------------------------------------------------------------------------------- 1 | # finch update 2 | 3 | Update one or more running containers 4 | 5 | ```text 6 | finch update [flags] CONTAINER [CONTAINER, ...] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --blkio-weight uint16 Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0) 13 | --cpu-period uint Limit CPU CFS (Completely Fair Scheduler) period 14 | --cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota (default -1) 15 | --cpu-shares uint CPU shares (relative weight) 16 | --cpus float Number of CPUs 17 | --cpuset-cpus string CPUs in which to allow execution (0-3, 0,1) 18 | --cpuset-mems string MEMs in which to allow execution (0-3, 0,1) 19 | -h, --help help for update 20 | --kernel-memory string Kernel memory limit (deprecated) 21 | -m, --memory string Memory limit 22 | --memory-reservation string Memory soft limit 23 | --memory-swap string Swap limit equal to memory plus swap: '-1' to enable unlimited swap 24 | --pids-limit int Tune container pids limit (set -1 for unlimited) (default -1) 25 | --restart string Restart policy to apply when a container exits (implemented values: "no"|"always|on-failure:n|unless-stopped") (default "no") 26 | ``` 27 | -------------------------------------------------------------------------------- /contrib/packaging/rpm/README.md: -------------------------------------------------------------------------------- 1 | # FinchRPM 2 | 3 | This package contains the spec file and supporting artifacts needed to build a Finch RPM for Amazon Linux. 4 | 5 | Currently, this RPM vends one top level package (`runfinch-finch`), which bundles a few other projects (`finch-buildkit`, `finch-soci`). These are bundled either because they don't provide packages on Amazon Linux or because they are not yet considered stable. In the future, if they are spun out into their own packages, `finch.spec` will be updated. 6 | 7 | ## Building 8 | 9 | This directory contains a `build.sh` script which takes a few options as input, allowing for building an RPM from the latest local commit, or building from the tip of a branch. By default, running just `./build.sh` will build the latest release specified in the `finch.spec` file. 10 | 11 | 1. `./build.sh` 12 | 1. Sets up the default directory structure needed to build RPMs, builds a Finch RPM, and moves it to the `_output` top level directory. By default, this requires internet access to download sources. 13 | 1. Install the newly built RPM (replace the version numbers and architecture as needed): 14 | 15 | ```shell 16 | cd ./_output 17 | sudo rpm -i \ 18 | runfinch-finch-1.2.2-1.amzn2int.0.1.x86_64.rpm 19 | ``` 20 | 21 | NOTE: To test changes, you will also first need to uninstall any existing version of the package using `sudo rpm -e`, or force install with `--force`. 22 | -------------------------------------------------------------------------------- /docs/snapshotters.md: -------------------------------------------------------------------------------- 1 | # Snapshotters Config Option 2 | 3 | ## Issue 4 | 5 | [#506](https://github.com/runfinch/finch/pull/506) 6 | 7 | ## Supported snapshotters 8 | 9 | - OverlayFS (default if none configured) 10 | - [SOCI](https://github.com/awslabs/soci-snapshotter) 11 | 12 | ## `snapshotters` option 13 | 14 | Users can use the snapshotters option at `${HOME}/.finch/finch.yaml` to set the snapshotters they would like to use. 15 | All snapshotters listed will be installed on the VM, and the first snapshotter listed will be made the default snapshotter. 16 | The default snapshotter will be used whenever a snapshotter is needed and not specified for a command. 17 | Any other listed snapshotters can be used by specifying them with the `--snapshotter` flag: 18 | 19 | ```console 20 | # finch pull ... # uses the default snapshotter 21 | # finch --snapshotter=mySnapshotter pull ... # uses mySnapshotter 22 | ``` 23 | 24 | ```yaml 25 | snapshotters: 26 | - overlayfs 27 | - soci 28 | 29 | # This example would set overlayfs as the default snapshotter and install SOCI on the VM so it can be used by the user if specified later. 30 | ``` 31 | 32 | To stop using a snapshotter, simply remove it from the `snapshotters` list. Snapshotters will not be automatically uninstalled from the VM once removed from the list. 33 | To remove it completely the user must shell into the VM and remove the binaries for the snapshotter from `usr/local/bin` 34 | -------------------------------------------------------------------------------- /pkg/path/finch_linux_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package path 7 | 8 | import ( 9 | "path/filepath" 10 | "testing" 11 | 12 | "github.com/stretchr/testify/assert" 13 | ) 14 | 15 | var mockFinch = Finch("mock_finch") 16 | 17 | func TestFinch_NewFinchPath(t *testing.T) { 18 | t.Parallel() 19 | assert.Equal(t, string(NewFinchPath()), filepath.Join("/", "etc", "finch")) 20 | } 21 | 22 | func TestFinch_FinchDir(t *testing.T) { 23 | t.Parallel() 24 | 25 | res := mockFinch.FinchDir() 26 | assert.Equal(t, res, string(mockFinch)) 27 | } 28 | 29 | func TestFinch_ConfigFilePath(t *testing.T) { 30 | t.Parallel() 31 | 32 | res := mockFinch.ConfigFilePath() 33 | assert.Equal(t, res, filepath.Join("mock_finch", "finch.yaml")) 34 | } 35 | 36 | func TestFinch_NerdctlConfigFilePath(t *testing.T) { 37 | t.Parallel() 38 | 39 | res := mockFinch.NerdctlConfigFilePath() 40 | assert.Equal(t, res, filepath.Join("mock_finch", "nerdctl", "nerdctl.toml")) 41 | } 42 | 43 | func TestFinch_BuildkitSocketPath(t *testing.T) { 44 | t.Parallel() 45 | 46 | res := mockFinch.BuildkitSocketPath() 47 | assert.Equal(t, res, filepath.Join("/", "var", "lib", "finch", "buildkit", "buildkitd.sock")) 48 | } 49 | 50 | func TestFinch_FinchDependencyBinDir(t *testing.T) { 51 | t.Parallel() 52 | 53 | res := mockFinch.FinchDependencyBinDir() 54 | assert.Equal(t, res, filepath.Join("/", "usr", "libexec", "finch")) 55 | } 56 | -------------------------------------------------------------------------------- /installer-builder/darwin/scripts/postinstall: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Post installation process started..." 4 | 5 | sudo pkill '^socket_vmnet' 6 | sudo pkill '^qemu-system-' 7 | sudo pkill '^limactl' 8 | 9 | #change permissions in home directory 10 | echo "Change permissions for product home directory." 11 | cd /Applications/Finch || exit 12 | chmod -R 777 . 13 | chmod -R 755 /Applications/Finch/dependencies/lima-socket_vmnet/opt/finch 14 | [ -d /usr/local/bin ] || mkdir /usr/local/bin 15 | 16 | #clean old artifacts 17 | sudo ln -sf /Applications/Finch/bin/finch /usr/local/bin/finch 18 | sudo rm -rf "/Applications/Finch/lima/data/finch/" 19 | sudo rm -rf "/Applications/Finch/lima/data/_config/override.yaml" 20 | sudo rm -rf "/Applications/Finch/lima/data/_config/default.yaml" 21 | sudo rm -rf "/Applications/Finch/lima/data/_config/user" 22 | sudo rm -rf "/Applications/Finch/lima/data/_config/user.pub" 23 | sudo rm -rf "/Applications/Finch/lima/data/_networks/" 24 | sudo rm -rf "/Applications/Finch/lima/data/_disks/" 25 | sudo rm -rf "/opt/finch/" 26 | sudo rm -rf "/private/var/run/finch-lima" 27 | sudo rm -rf "/private/etc/sudoers.d/finch-lima" 28 | 29 | # Forget previous pkgutil packages starting with org.Finch except for the current version 30 | echo "Remove historical pkgutil packages..." 31 | pkgutil --pkgs | grep '^org\.Finch\.' | grep -v '^org\.Finch\.__VERSION__' | while read -r pkg; do 32 | echo "Forgetting package $pkg" 33 | sudo pkgutil --forget "$pkg" 34 | done 35 | 36 | echo "Post installation process finished." 37 | -------------------------------------------------------------------------------- /pkg/support/config_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package support 5 | 6 | import ( 7 | "path/filepath" 8 | "runtime" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | 13 | fpath "github.com/runfinch/finch/pkg/path" 14 | ) 15 | 16 | func TestNewBundleConfig(t *testing.T) { 17 | t.Parallel() 18 | 19 | finch := fpath.Finch("/mockfinch") 20 | homeDir := "/mockhome" 21 | NewBundleConfig(finch, homeDir) 22 | } 23 | 24 | func TestBundleConfig_LogFiles(t *testing.T) { 25 | t.Parallel() 26 | 27 | var homeDir string 28 | var finch fpath.Finch 29 | if runtime.GOOS == "windows" { 30 | finch = fpath.Finch("C:\\mockfinch") 31 | homeDir = "C:\\mockhome" 32 | } else { 33 | finch = fpath.Finch("/mockfinch") 34 | homeDir = "/mockhome" 35 | } 36 | 37 | config := NewBundleConfig(finch, homeDir) 38 | 39 | for _, fileName := range config.LogFiles() { 40 | assert.True(t, filepath.IsAbs(fileName)) 41 | } 42 | } 43 | 44 | func TestBundleConfig_ConfigFiles(t *testing.T) { 45 | t.Parallel() 46 | 47 | var homeDir string 48 | var finch fpath.Finch 49 | if runtime.GOOS == "windows" { 50 | finch = fpath.Finch("C:\\mockfinch") 51 | homeDir = "C:\\mockhome" 52 | } else { 53 | finch = fpath.Finch("/mockfinch") 54 | homeDir = "/mockhome" 55 | } 56 | config := NewBundleConfig(finch, homeDir) 57 | 58 | for _, fileName := range config.ConfigFiles() { 59 | assert.True(t, filepath.IsAbs(fileName)) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pkg/command/exit_error_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package command 5 | 6 | import ( 7 | "errors" 8 | "os/exec" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | func TestWrapIfExitError(t *testing.T) { 15 | t.Parallel() 16 | 17 | testCases := []struct { 18 | name string 19 | in error 20 | want error 21 | }{ 22 | { 23 | name: "the original error should be returned if it is not of type *exec.ExitError", 24 | in: errors.New("I am not an *exec.ExitError"), 25 | want: errors.New("I am not an *exec.ExitError"), 26 | }, 27 | { 28 | name: "the error should be wrapped if it is of type *exec.ExitError", 29 | in: &exec.ExitError{Stderr: []byte("stderr")}, 30 | want: &exitError{wrapped: &exec.ExitError{Stderr: []byte("stderr")}}, 31 | }, 32 | } 33 | 34 | for _, tc := range testCases { 35 | t.Run(tc.name, func(t *testing.T) { 36 | t.Parallel() 37 | 38 | assert.Equal(t, tc.want, wrapIfExitError(tc.in)) 39 | }) 40 | } 41 | } 42 | 43 | func TestExitError_Error(t *testing.T) { 44 | t.Parallel() 45 | 46 | want := ", stderr: some error" 47 | got := newExitError(&exec.ExitError{Stderr: []byte("some error")}).Error() 48 | assert.Equal(t, got, want) 49 | } 50 | 51 | func TestExitError_Unwrap(t *testing.T) { 52 | t.Parallel() 53 | 54 | want := &exec.ExitError{Stderr: []byte("some error")} 55 | got := newExitError(want).Unwrap() 56 | assert.Equal(t, got, want) 57 | } 58 | -------------------------------------------------------------------------------- /pkg/command/exec.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package command 5 | 6 | import ( 7 | "io" 8 | "os/exec" 9 | ) 10 | 11 | // ExecCmdCreator implements CommandCreator by invoking functions offered by os/exec. 12 | type ExecCmdCreator struct{} 13 | 14 | var _ Creator = (*ExecCmdCreator)(nil) 15 | 16 | // NewExecCmdCreator creates a new ExecCmdCreator. 17 | func NewExecCmdCreator() *ExecCmdCreator { 18 | return &ExecCmdCreator{} 19 | } 20 | 21 | // Create creates a new Command. 22 | func (ecc *ExecCmdCreator) Create(name string, args ...string) Command { 23 | return newExecCmd(name, args...) 24 | } 25 | 26 | func newExecCmd(name string, args ...string) *execCmd { 27 | return &execCmd{ 28 | exec.Command(name, args...), 29 | } 30 | } 31 | 32 | type execCmd struct { 33 | *exec.Cmd 34 | } 35 | 36 | var _ Command = (*execCmd)(nil) 37 | 38 | func (c *execCmd) String() string { 39 | return c.Cmd.String() 40 | } 41 | 42 | func (c *execCmd) Output() ([]byte, error) { 43 | b, err := c.Cmd.Output() 44 | return b, wrapIfExitError(err) 45 | } 46 | 47 | func (c *execCmd) SetEnv(env []string) { 48 | c.Env = env 49 | } 50 | 51 | func (c *execCmd) SetStdin(stdin io.Reader) { 52 | c.Stdin = stdin 53 | } 54 | 55 | func (c *execCmd) SetStdout(stdout io.Writer) { 56 | c.Stdout = stdout 57 | } 58 | 59 | func (c *execCmd) SetStderr(stderr io.Writer) { 60 | c.Stderr = stderr 61 | } 62 | 63 | func (c *execCmd) StdinPipe() (io.WriteCloser, error) { 64 | return c.Cmd.StdinPipe() 65 | } 66 | -------------------------------------------------------------------------------- /pkg/path/finch_windows_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | // +build windows 6 | 7 | package path 8 | 9 | import ( 10 | "fmt" 11 | "testing" 12 | 13 | "github.com/stretchr/testify/assert" 14 | "go.uber.org/mock/gomock" 15 | 16 | "github.com/runfinch/finch/pkg/mocks" 17 | ) 18 | 19 | func TestFinch_RootDir(t *testing.T) { 20 | t.Parallel() 21 | 22 | testCases := []struct { 23 | name string 24 | mockSvc func(*mocks.FinchFinderDeps) 25 | wantErr error 26 | want Finch 27 | }{ 28 | { 29 | name: "happy path", 30 | wantErr: nil, 31 | want: Finch(`C:\Users\User\AppData\`), 32 | mockSvc: func(deps *mocks.FinchFinderDeps) { 33 | deps.EXPECT().Env("LOCALAPPDATA").Return(`C:\Users\User\AppData\`) 34 | }, 35 | }, 36 | { 37 | name: "failed to find the executable path", 38 | want: "", 39 | wantErr: fmt.Errorf("unexpected LOCALAPPDATA path %q", `\\network.path\home\test\"&someDir`), 40 | mockSvc: func(deps *mocks.FinchFinderDeps) { 41 | deps.EXPECT().Env("LOCALAPPDATA").Return(`\\network.path\home\test\"&someDir`) 42 | }, 43 | }, 44 | } 45 | 46 | for _, tc := range testCases { 47 | t.Run(tc.name, func(t *testing.T) { 48 | t.Parallel() 49 | 50 | ctrl := gomock.NewController(t) 51 | deps := mocks.NewFinchFinderDeps(ctrl) 52 | tc.mockSvc(deps) 53 | res, err := mockFinch.FinchRootDir(deps) 54 | assert.Equal(t, Finch(res), tc.want) 55 | assert.Equal(t, err, tc.wantErr) 56 | }) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pkg/config/validate_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package config 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/docker/go-units" 12 | 13 | "github.com/runfinch/finch/pkg/flog" 14 | "github.com/runfinch/finch/pkg/fmemory" 15 | ) 16 | 17 | func validate(cfg *Finch, log flog.Logger, systemDeps LoadSystemDeps, mem fmemory.Memory) error { 18 | if *cfg.CPUs <= 0 { 19 | return fmt.Errorf( 20 | "specified number of CPUs (%d) must be greater than 0", 21 | *cfg.CPUs, 22 | ) 23 | } 24 | 25 | memInt, err := units.FromHumanSize(*cfg.Memory) 26 | if err != nil { 27 | return fmt.Errorf("failed to parse memory to uint: %w", err) 28 | } 29 | 30 | if memInt <= 0 { 31 | return fmt.Errorf( 32 | "specified amount of memory (%s) must be greater than 0GiB", 33 | *cfg.Memory, 34 | ) 35 | } 36 | 37 | totalCPUs := systemDeps.NumCPU() 38 | if *cfg.CPUs > totalCPUs { 39 | log.Infof( 40 | "The specified number of CPUs (%d) is greater than CPUs available on this system (%d),\n"+ 41 | "which may lead to severe performance degradation", 42 | *cfg.CPUs, 43 | totalCPUs, 44 | ) 45 | } 46 | 47 | totalMem := mem.TotalMemory() 48 | if uint64(memInt) > totalMem { 49 | log.Infof( 50 | "The specified amount of memory (%s) is greater than the memory available on this system (%s),\n"+ 51 | "which may lead to severe performance degradation", 52 | *cfg.Memory, 53 | units.BytesSize(float64(totalMem)), 54 | ) 55 | } 56 | 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /contrib/packaging/deb/README.md: -------------------------------------------------------------------------------- 1 | # Finch Deb 2 | 3 | This package contains the bash script and supporting artifacts needed to build a Finch Debian archive. 4 | 5 | Currently, this DEB vends one top level package (`runfinch-finch`), which bundles a few other projects (`nerdctl`, `finch-buildkit`, `finch-soci`, `cni`, `cosign`). These are bundled either because they don't provide Debian packages or because they are not yet considered stable. In the future, if they are spun out into their own packages, `package.sh` and `control` will be updated. Packages, such as `containerd` and `runc`, which currently provide stable Debian packages, are declared as dependencies in the `control` file. 6 | 7 | ## Building 8 | 9 | This directory contains a `package.sh` script which takes a few options as input, allowing for building a .deb on either `amd64` or `arm64`. By default, running just `./package.sh` will build for both architecture's and set the version to `0.0.0`. 10 | 11 | 1. `./package.sh` 12 | 1. Sets up the default directory structure needed to build .deb's, builds a Finch .deb, and moves it to the `_output/deb/` top level directory. By default, this requires internet access to download sources. 13 | 1. Install the newly built .deb (replace the version numbers and architecture as needed): 14 | 15 | ```shell 16 | ./contrib/packaging/deb/package.sh --amd64 --version 1.0.0 17 | cd ./_output/deb 18 | sudo apt install runfinch-finch_1.0.0_amd64.deb 19 | ``` 20 | 21 | NOTE: To test changes, you will also first need to uninstall any existing version of the package using `sudo apt remove runfinch-finch`. 22 | -------------------------------------------------------------------------------- /pkg/path/finch_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package path 7 | 8 | import ( 9 | "path/filepath" 10 | ) 11 | 12 | // NewFinchPath returns the path to the Finch root directory. 13 | func NewFinchPath() Finch { 14 | return Finch(filepath.Join("/", "etc", "finch")) 15 | } 16 | 17 | // FinchDir returns the path to the Finch config directory. 18 | func (fp Finch) FinchDir() string { 19 | return string(fp) 20 | } 21 | 22 | // ConfigFilePath returns the path to Finch config file. 23 | func (fp Finch) ConfigFilePath() string { 24 | return filepath.Join(string(fp), "finch.yaml") 25 | } 26 | 27 | // NerdctlConfigFilePath returns the path to Finch config file. 28 | func (fp Finch) NerdctlConfigFilePath() string { 29 | return filepath.Join(string(fp), "nerdctl", "nerdctl.toml") 30 | } 31 | 32 | // BuildkitSocketPath returns the path to the Buildkit socket file. 33 | func (fp Finch) BuildkitSocketPath() string { 34 | return filepath.Join(fp.FinchRuntimeDataDir(), "buildkit", "buildkitd.sock") 35 | } 36 | 37 | // FinchDependencyBinDir returns the path to Finch's local helper or dependency binaries. 38 | // Currently used for vended version of BuildKit. 39 | func (Finch) FinchDependencyBinDir() string { 40 | return filepath.Join("/", "usr", "libexec", "finch") 41 | } 42 | 43 | // FinchRuntimeDataDir returns the path to Finch's runtime data directory, used for state of running programs. 44 | func (Finch) FinchRuntimeDataDir() string { 45 | return filepath.Join("/", "var", "lib", "finch") 46 | } 47 | -------------------------------------------------------------------------------- /cmd/finch/virtual_machine_disk_info.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "strings" 11 | 12 | "github.com/spf13/cobra" 13 | 14 | "github.com/runfinch/finch/pkg/command" 15 | "github.com/runfinch/finch/pkg/flog" 16 | ) 17 | 18 | func newVMDiskInfoCommand(creator command.NerdctlCmdCreator, logger flog.Logger) *cobra.Command { 19 | cmd := &cobra.Command{ 20 | Use: "info", 21 | Short: "Display information about the virtual machine disk", 22 | RunE: newDiskInfoAction(creator, logger).runAdapter, 23 | } 24 | return cmd 25 | } 26 | 27 | type diskInfoAction struct { 28 | creator command.NerdctlCmdCreator 29 | logger flog.Logger 30 | } 31 | 32 | func newDiskInfoAction(creator command.NerdctlCmdCreator, logger flog.Logger) *diskInfoAction { 33 | return &diskInfoAction{ 34 | creator: creator, 35 | logger: logger, 36 | } 37 | } 38 | 39 | func (dia *diskInfoAction) runAdapter(_ *cobra.Command, _ []string) error { 40 | return dia.run() 41 | } 42 | 43 | func (dia *diskInfoAction) run() error { 44 | limaCmd := dia.creator.CreateWithoutStdio("disk", "ls", limaInstanceName) 45 | output, err := limaCmd.CombinedOutput() 46 | if err != nil { 47 | return fmt.Errorf("failed to get disk information: %w\n%s", err, output) 48 | } 49 | 50 | if len(strings.TrimSpace(string(output))) == 0 { 51 | return fmt.Errorf("no disk information found for virtual machine %q", limaInstanceName) 52 | } 53 | 54 | fmt.Print(string(output)) 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /cmd/finch/version_remote.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package main 7 | 8 | import ( 9 | "encoding/json" 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/runfinch/finch/pkg/lima" 14 | ) 15 | 16 | func (va *versionAction) printVersion(format string) error { 17 | status, err := lima.GetVMStatus(va.creator, va.logger, limaInstanceName) 18 | if err != nil { 19 | return fmt.Errorf("failed to get VM status: %w", err) 20 | } 21 | if status != lima.Running { 22 | return errors.New("detailed version info is unavailable because VM is not running") 23 | } 24 | // Add -E to sudo command in order to preserve existing environment variables, more info: 25 | // https://stackoverflow.com/questions/8633461/how-to-keep-environment-variables-when-using-sudo/8633575#8633575 26 | limaArgs := []string{"shell", limaInstanceName, "sudo", "-E", "nerdctl", "version", "--format", "json"} 27 | out, err := va.creator.CreateWithoutStdio(limaArgs...).Output() 28 | if err != nil { 29 | return fmt.Errorf("failed to create the nerdctl version command: %w", err) 30 | } 31 | 32 | var nerdctlVersion NerdctlVersionOutput 33 | err = json.Unmarshal(out, &nerdctlVersion) 34 | if err != nil { 35 | return fmt.Errorf("failed to JSON-unmarshal the nerdctl version output: %w", err) 36 | } 37 | 38 | tmpl, err := newVersionTemplate(format) 39 | if err != nil { 40 | return err 41 | } 42 | err = va.showVersionMessage(tmpl, nerdctlVersion) 43 | if err != nil { 44 | return err 45 | } 46 | 47 | return nil 48 | } 49 | -------------------------------------------------------------------------------- /cmd/finch/virtual_machine_settings_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package main 7 | 8 | import ( 9 | "io" 10 | 11 | "github.com/runfinch/finch/pkg/config" 12 | "github.com/runfinch/finch/pkg/flog" 13 | 14 | "github.com/spf13/afero" 15 | "github.com/spf13/cobra" 16 | ) 17 | 18 | func newSettingsVMCommand( 19 | logger flog.Logger, 20 | lca config.LimaConfigApplier, 21 | fs afero.Fs, 22 | stdout io.Writer, 23 | ) *cobra.Command { 24 | settingsVMCommand := &cobra.Command{ 25 | Use: "settings", 26 | Short: "Disabled on Windows as there are currently no configurable VM settings", 27 | Hidden: true, 28 | RunE: newSettingsVMAction(logger, lca, fs, stdout).runAdapter, 29 | } 30 | 31 | return settingsVMCommand 32 | } 33 | 34 | type settingsVMAction struct { 35 | logger flog.Logger 36 | limaConfigApplier config.LimaConfigApplier 37 | fs afero.Fs 38 | stdout io.Writer 39 | } 40 | 41 | func newSettingsVMAction( 42 | logger flog.Logger, 43 | lca config.LimaConfigApplier, 44 | fs afero.Fs, 45 | stdout io.Writer, 46 | ) *settingsVMAction { 47 | return &settingsVMAction{ 48 | logger: logger, 49 | limaConfigApplier: lca, 50 | fs: fs, 51 | stdout: stdout, 52 | } 53 | } 54 | 55 | func (sva *settingsVMAction) runAdapter(_ *cobra.Command, _ []string) error { 56 | return sva.run(config.VMConfigOpts{}) 57 | } 58 | 59 | func (sva *settingsVMAction) run(_ config.VMConfigOpts) error { 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /cmd/finch/virtual_machine_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package main 7 | 8 | import ( 9 | "os" 10 | 11 | "github.com/spf13/afero" 12 | "github.com/spf13/cobra" 13 | 14 | "github.com/runfinch/finch/pkg/command" 15 | "github.com/runfinch/finch/pkg/config" 16 | "github.com/runfinch/finch/pkg/dependency" 17 | "github.com/runfinch/finch/pkg/disk" 18 | "github.com/runfinch/finch/pkg/flog" 19 | "github.com/runfinch/finch/pkg/path" 20 | ) 21 | 22 | func newVirtualMachineCommand( 23 | limaCmdCreator command.NerdctlCmdCreator, 24 | logger flog.Logger, 25 | optionalDepGroups []*dependency.Group, 26 | lca config.LimaConfigApplier, 27 | nca config.NerdctlConfigApplier, 28 | fp path.Finch, 29 | fs afero.Fs, 30 | diskManager disk.UserDataDiskManager, 31 | ) *cobra.Command { 32 | virtualMachineCommand := &cobra.Command{ 33 | Use: virtualMachineRootCmd, 34 | Short: "Manage the virtual machine lifecycle", 35 | } 36 | 37 | virtualMachineCommand.AddCommand( 38 | newStartVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fs, fp.LimaSSHPrivateKeyPath(), diskManager), 39 | newStopVMCommand(limaCmdCreator, diskManager, logger), 40 | newRemoveVMCommand(limaCmdCreator, diskManager, logger), 41 | newStatusVMCommand(limaCmdCreator, logger, os.Stdout), 42 | newInitVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fp.BaseYamlFilePath(), fs, 43 | fp.LimaSSHPrivateKeyPath(), diskManager), 44 | newSettingsVMCommand(logger, lca, fs, os.Stdout), 45 | ) 46 | 47 | return virtualMachineCommand 48 | } 49 | -------------------------------------------------------------------------------- /docs/cmd/finch_push.md: -------------------------------------------------------------------------------- 1 | # finch push 2 | 3 | Push an image or a repository to a registry. Optionally specify "ipfs://" or "ipns://" scheme to push image to IPFS. 4 | 5 | ```text 6 | finch push [flags] NAME[:TAG] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --all-platforms Push content for all platforms 13 | --allow-nondistributable-artifacts Allow pushing images with non-distributable blobs 14 | --cosign-key string Path to the private key file, KMS URI or Kubernetes Secret for --sign=cosign 15 | --estargz Convert the image into eStargz 16 | -h, --help help for push 17 | --ipfs-address string multiaddr of IPFS API (default uses $IPFS_PATH env variable if defined or local directory ~/.ipfs) 18 | --ipfs-ensure-image Ensure the entire contents of the image is locally available before push (default true) 19 | --notation-key-name string Signing key name for a key previously added to notation's key list for --sign=notation 20 | --platform strings Push content for a specific platform 21 | -q, --quiet Suppress verbose output 22 | --sign string Sign the image (none|cosign|notation (default "none") 23 | --soci-min-layer-size int Minimum layer size to build zTOC for. Smaller layers won't have zTOC and not lazy pulled. Default is 10 MiB. (default -1) 24 | --soci-span-size int Span size that soci index uses to segment layer data. Default is 4 MiB. (default -1) 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/cmd/finch_logs.md: -------------------------------------------------------------------------------- 1 | # finch logs 2 | 3 | Fetch the logs of a container. 4 | 5 | The following containers are supported: 6 | - Containers created with 'finch run -d'. The log is currently empty for containers created without '-d'. 7 | - Containers created with 'finch compose'. 8 | - Containers created with Kubernetes (EXPERIMENTAL). 9 | 10 | ```text 11 | finch logs [flags] CONTAINER 12 | ``` 13 | 14 | ## Options 15 | 16 | ```text 17 | -f, --follow Follow log output 18 | -h, --help help for logs 19 | --since string Show logs since timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) 20 | -n, --tail string Number of lines to show from the end of the logs (default "all") 21 | -t, --timestamps Show timestamps 22 | --until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37Z) or relative (e.g. 42m for 42 minutes) 23 | ``` 24 | 25 | ### Note 26 | When running containers in detached mode (`run -d`) or in interactive mode (`run -it`) logs are persisted to a JSON log file by default, these can be accessed via the `finch logs` command. 27 | 28 | When starting containers in attached mode (`start -a`), logs are directed to stdout and stderr of the terminal session. In this scenario: 29 | 30 | - Logs are not persisted to a file by default. 31 | - Users are responsible for log persistence if required. 32 | 33 | ### Important Considerations 34 | 35 | - The default logging behavior can be overridden using logging options provided by finch. 36 | - For long-running applications or when log persistence is crucial, consider using detached mode or implementing a custom logging solution when using attached mode. -------------------------------------------------------------------------------- /installer-builder/darwin/Resources/conclusion.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |

Finch

10 |

Thank you for installing Finch.

11 |
Run Finch
12 |

Open a new terminal and run the following command to get the virtual machine:

13 |   $ finch vm init 14 |
15 |
16 |
17 |
Resources:
18 |

Go through the following links for additional information:

19 | 22 |
23 |
24 |
25 |
Uninstall Finch
26 |

Run the following command to uninstall Finch:
27 |
  $ sudo bash /Applications/Finch/uninstall.sh
28 |

29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /pkg/config/defaults_linux_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build linux 5 | 6 | package config 7 | 8 | import ( 9 | "testing" 10 | 11 | "github.com/stretchr/testify/require" 12 | "go.uber.org/mock/gomock" 13 | 14 | "github.com/runfinch/finch/pkg/mocks" 15 | ) 16 | 17 | type applyDefaultTestCases []struct { 18 | name string 19 | cfg *Finch 20 | mockSvc func( 21 | deps *mocks.LoadSystemDeps, 22 | mem *mocks.Memory, 23 | ecc *mocks.CommandCreator, 24 | ctrl *gomock.Controller, 25 | ) 26 | want *Finch 27 | } 28 | 29 | func Test_applyDefaults(t *testing.T) { 30 | t.Parallel() 31 | 32 | testCases := []struct { 33 | name string 34 | cfg *Finch 35 | mockSvc func( 36 | deps *mocks.LoadSystemDeps, 37 | mem *mocks.Memory, 38 | ecc *mocks.CommandCreator, 39 | ctrl *gomock.Controller, 40 | ) 41 | want *Finch 42 | }{ 43 | { 44 | name: "happy path", 45 | cfg: &Finch{}, 46 | mockSvc: func( 47 | deps *mocks.LoadSystemDeps, 48 | mem *mocks.Memory, 49 | ecc *mocks.CommandCreator, 50 | ctrl *gomock.Controller, 51 | ) { 52 | }, 53 | want: &Finch{}, 54 | }, 55 | } 56 | 57 | for _, tc := range testCases { 58 | t.Run(tc.name, func(t *testing.T) { 59 | t.Parallel() 60 | 61 | ctrl := gomock.NewController(t) 62 | deps := mocks.NewLoadSystemDeps(ctrl) 63 | mem := mocks.NewMemory(ctrl) 64 | ecc := mocks.NewCommandCreator(ctrl) 65 | 66 | tc.mockSvc(deps, mem, ecc, ctrl) 67 | 68 | got := applyDefaults(tc.cfg, deps, mem, ecc) 69 | require.Equal(t, tc.want, got) 70 | }) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /docs/cmd/finch_container.md: -------------------------------------------------------------------------------- 1 | # finch container 2 | 3 | Manage containers 4 | 5 | ```text 6 | finch container [flags] 7 | ``` 8 | 9 | ## Commands 10 | 11 | ```text 12 | attach Attach stdin, stdout, and stderr to a running container. 13 | commit Create a new image from a container's changes 14 | cp Copy files/folders between a running container and the local filesystem. 15 | create Create a new container. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS. 16 | exec Run a command in a running container 17 | inspect Display detailed information on one or more containers. 18 | kill Kill one or more running containers 19 | logs Fetch the logs of a container. Expected to be used with 'finch run -d'. 20 | ls List containers 21 | pause Pause all processes within one or more containers 22 | port List port mappings or a specific mapping for the container 23 | prune Remove all stopped containers 24 | rename rename a container 25 | restart Restart one or more running containers 26 | rm Remove one or more containers 27 | run Run a command in a new container. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS. 28 | start Start one or more running containers 29 | stats Display a live stream of container(s) resource usage statistics. 30 | stop Stop one or more running containers 31 | unpause Unpause all processes within one or more containers 32 | update Update one or more running containers 33 | wait Block until one or more containers stop, then print their exit codes. 34 | ``` 35 | 36 | ## Options 37 | 38 | ```text 39 | -h, --help help for container 40 | ``` 41 | -------------------------------------------------------------------------------- /contrib/hello-finch/main.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc or its affiliates. All rights reserved. 2 | package main 3 | 4 | import ( 5 | "fmt" 6 | ) 7 | 8 | const hello = ` 9 | @@@@@@@@@@@@@@@@@@@ 10 | @@@@@@@@@@@@ @@@@@@@@@@@ 11 | @@@@@@@ @@@@@@@ 12 | @@@@@@ @@@@@@ 13 | @@@@@@ @@@@@ 14 | @@@@@ @@@# @@@@@@@@@ 15 | @@@@@ @@ @@@ @@@@@@@@@@ 16 | @@@@% @ @@ @@@@@@@@@@@ 17 | @@@@ @@@@@@@@ 18 | @@@@ @@@@@@@@@@@& 19 | @@@@@ &@@@@@@@@@@@ 20 | @@@@@ @@@@@@@@ 21 | @@@@@ @@@@@( 22 | @@@@@@ @@@@@@ 23 | @@@@@@@ @@@@@@@ 24 | @@@@@@@@@@@@@@@@@@@@@@@@@@ 25 | @@@@@@@@@@@@@@@@@@` 26 | 27 | func main() { 28 | fmt.Println(hello) 29 | fmt.Println("\n\nHello from Finch!\n") 30 | fmt.Println("Visit us @ github.com/runfinch\n") 31 | } 32 | -------------------------------------------------------------------------------- /cmd/finch/main.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package main denotes the entry point of finch CLI. 5 | package main 6 | 7 | import ( 8 | "os" 9 | 10 | "github.com/containerd/nerdctl/v2/pkg/errutil" 11 | "github.com/spf13/afero" 12 | "github.com/spf13/cobra" 13 | 14 | "github.com/runfinch/finch/pkg/command" 15 | "github.com/runfinch/finch/pkg/config" 16 | "github.com/runfinch/finch/pkg/flog" 17 | "github.com/runfinch/finch/pkg/fmemory" 18 | "github.com/runfinch/finch/pkg/system" 19 | ) 20 | 21 | const finchRootCmd = "finch" 22 | 23 | func main() { 24 | logger := flog.NewLogrus() 25 | stdLib := system.NewStdLib() 26 | fs := afero.NewOsFs() 27 | mem := fmemory.NewMemory() 28 | stdOut := os.Stdout 29 | if err := xmain(logger, stdLib, fs, stdLib, mem, stdOut); err != nil { 30 | errutil.HandleExitCoder(err) 31 | logger.Fatal(err) 32 | } 33 | } 34 | 35 | func initializeNerdctlCommands( 36 | ncc command.NerdctlCmdCreator, 37 | ecc command.Creator, 38 | logger flog.Logger, 39 | fs afero.Fs, 40 | fc *config.Finch, 41 | ) []*cobra.Command { 42 | nerdctlCommandCreator := newNerdctlCommandCreator(ncc, ecc, system.NewStdLib(), logger, fs, fc) 43 | var allNerdctlCommands []*cobra.Command 44 | for cmdName, cmdDescription := range nerdctlCmds { 45 | allNerdctlCommands = append(allNerdctlCommands, nerdctlCommandCreator.create(cmdName, cmdDescription)) 46 | } 47 | 48 | if fc != nil && fc.DockerCompat { 49 | for cmdName, cmdDescription := range dockerCompatCmds { 50 | allNerdctlCommands = append(allNerdctlCommands, nerdctlCommandCreator.create(cmdName, cmdDescription)) 51 | } 52 | } 53 | 54 | return allNerdctlCommands 55 | } 56 | -------------------------------------------------------------------------------- /finch.yaml.d/mac.yaml: -------------------------------------------------------------------------------- 1 | provision: 2 | - mode: boot 3 | script: | 4 | systemctl stop NetworkManager-wait-online.service 5 | systemctl reset-failed NetworkManager-wait-online.service 6 | systemctl mask NetworkManager-wait-online.service 7 | - mode: boot 8 | script: | 9 | modprobe virtiofs 10 | # port this to common.yaml after windows socket forwarding is added 11 | - mode: user 12 | script: | 13 | sudo cp /usr/local/bin/finch-daemon 14 | sudo cp /usr/bin/docker-credential-finch 15 | sudo cp /finch@.service /usr/local/lib/systemd/system/finch@.service 16 | 17 | sudo systemctl daemon-reload 18 | sudo systemctl enable --now finch@${UID} 19 | mounts: 20 | - location: "~" 21 | mountPoint: null 22 | writable: true 23 | sshfs: 24 | cache: true 25 | followSymlinks: false 26 | sftpDriver: "openssh-sftp-server" 27 | 9p: 28 | securityModel: "none" 29 | protocolVersion: "9p2000.L" 30 | msize: "128KiB" 31 | cache: "fscache" 32 | - location: "/tmp/lima" 33 | writable: true 34 | - location: "/private" 35 | writable: true 36 | - location: "/var/folders" 37 | writable: true 38 | 39 | ssh: 40 | localPort: 0 41 | loadDotSSHPubKeys: false 42 | forwardAgent: true 43 | forwardX11: false 44 | forwardX11Trusted: false 45 | 46 | firmware: 47 | legacyBIOS: false 48 | 49 | video: 50 | display: "none" 51 | 52 | hostResolver: 53 | hosts: 54 | host.finch.internal: host.lima.internal 55 | host.docker.internal: host.lima.internal 56 | 57 | portForwards: 58 | - guestSocket: "/run/finch.sock" 59 | hostSocket: "{{.Dir}}/sock/finch.sock" 60 | -------------------------------------------------------------------------------- /pkg/mocks/pkg_fmemory_memory.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Code generated by MockGen. DO NOT EDIT. 5 | // Source: github.com/runfinch/finch/pkg/fmemory (interfaces: Memory) 6 | // 7 | // Generated by this command: 8 | // 9 | // mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_fmemory_memory.go -package=mocks -mock_names Memory=Memory . Memory 10 | // 11 | 12 | // Package mocks is a generated GoMock package. 13 | package mocks 14 | 15 | import ( 16 | reflect "reflect" 17 | 18 | gomock "go.uber.org/mock/gomock" 19 | ) 20 | 21 | // Memory is a mock of Memory interface. 22 | type Memory struct { 23 | ctrl *gomock.Controller 24 | recorder *MemoryMockRecorder 25 | isgomock struct{} 26 | } 27 | 28 | // MemoryMockRecorder is the mock recorder for Memory. 29 | type MemoryMockRecorder struct { 30 | mock *Memory 31 | } 32 | 33 | // NewMemory creates a new mock instance. 34 | func NewMemory(ctrl *gomock.Controller) *Memory { 35 | mock := &Memory{ctrl: ctrl} 36 | mock.recorder = &MemoryMockRecorder{mock} 37 | return mock 38 | } 39 | 40 | // EXPECT returns an object that allows the caller to indicate expected use. 41 | func (m *Memory) EXPECT() *MemoryMockRecorder { 42 | return m.recorder 43 | } 44 | 45 | // TotalMemory mocks base method. 46 | func (m *Memory) TotalMemory() uint64 { 47 | m.ctrl.T.Helper() 48 | ret := m.ctrl.Call(m, "TotalMemory") 49 | ret0, _ := ret[0].(uint64) 50 | return ret0 51 | } 52 | 53 | // TotalMemory indicates an expected call of TotalMemory. 54 | func (mr *MemoryMockRecorder) TotalMemory() *gomock.Call { 55 | mr.mock.ctrl.T.Helper() 56 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TotalMemory", reflect.TypeOf((*Memory)(nil).TotalMemory)) 57 | } 58 | -------------------------------------------------------------------------------- /cmd/finch/virtual_machine_disk_resize.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | 11 | "github.com/spf13/cobra" 12 | 13 | "github.com/runfinch/finch/pkg/command" 14 | "github.com/runfinch/finch/pkg/flog" 15 | ) 16 | 17 | func newVMDiskResizeCommand(limaCmdCreator command.NerdctlCmdCreator, logger flog.Logger) *cobra.Command { 18 | var size string 19 | cmd := &cobra.Command{ 20 | Use: "resize", 21 | Short: "Resize the virtual machine disk", 22 | RunE: newVMDiskResizeAction(limaCmdCreator, logger).runAdapter, 23 | } 24 | cmd.Flags().StringVar(&size, "size", "", "New size for the disk (required)") 25 | _ = cmd.MarkFlagRequired("size") 26 | return cmd 27 | } 28 | 29 | type diskResizeVMAction struct { 30 | logger flog.Logger 31 | creator command.NerdctlCmdCreator 32 | } 33 | 34 | func newVMDiskResizeAction(limaCmdCreator command.NerdctlCmdCreator, logger flog.Logger) *diskResizeVMAction { 35 | return &diskResizeVMAction{ 36 | logger: logger, 37 | creator: limaCmdCreator, 38 | } 39 | } 40 | 41 | func (dva *diskResizeVMAction) runAdapter(cmd *cobra.Command, _ []string) error { 42 | size, err := cmd.Flags().GetString("size") 43 | if err != nil { 44 | return err 45 | } 46 | return dva.run(size) 47 | } 48 | 49 | func (dva *diskResizeVMAction) run(size string) error { 50 | dva.logger.Infof("Resizing disk to %s...", size) 51 | 52 | limaCmd := dva.creator.CreateWithoutStdio("disk", "resize", limaInstanceName, "--size", size) 53 | output, err := limaCmd.CombinedOutput() 54 | if err != nil { 55 | return fmt.Errorf("failed to resize disk: %w\n%s", err, output) 56 | } 57 | 58 | dva.logger.Info("Disk resized successfully.") 59 | return nil 60 | } 61 | -------------------------------------------------------------------------------- /cmd/finch/virtual_machine_status.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "io" 11 | 12 | "github.com/runfinch/finch/pkg/command" 13 | "github.com/runfinch/finch/pkg/flog" 14 | "github.com/runfinch/finch/pkg/lima" 15 | 16 | "github.com/spf13/cobra" 17 | ) 18 | 19 | func newStatusVMCommand(limaCmdCreator command.NerdctlCmdCreator, logger flog.Logger, stdout io.Writer) *cobra.Command { 20 | statusVMCommand := &cobra.Command{ 21 | Use: "status", 22 | Short: "Status of the virtual machine", 23 | RunE: newStatusVMAction(limaCmdCreator, logger, stdout).runAdapter, 24 | } 25 | 26 | return statusVMCommand 27 | } 28 | 29 | type statusVMAction struct { 30 | creator command.NerdctlCmdCreator 31 | logger flog.Logger 32 | stdout io.Writer 33 | } 34 | 35 | func newStatusVMAction(creator command.NerdctlCmdCreator, logger flog.Logger, stdout io.Writer) *statusVMAction { 36 | return &statusVMAction{creator: creator, logger: logger, stdout: stdout} 37 | } 38 | 39 | func (sva *statusVMAction) runAdapter(_ *cobra.Command, _ []string) error { 40 | return sva.run() 41 | } 42 | 43 | func (sva *statusVMAction) run() error { 44 | status, err := lima.GetVMStatus(sva.creator, sva.logger, limaInstanceName) 45 | if err != nil { 46 | return err 47 | } 48 | switch status { 49 | case lima.Running: 50 | _, err = fmt.Fprintln(sva.stdout, "Running") 51 | return err 52 | case lima.Nonexistent: 53 | _, err = fmt.Fprintln(sva.stdout, "Nonexistent") 54 | return err 55 | case lima.Stopped: 56 | _, err = fmt.Fprintln(sva.stdout, "Stopped") 57 | return err 58 | default: 59 | return fmt.Errorf("instance state of %q is unknown", limaInstanceName) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pkg/disk/disk.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | // Package disk manages the persistent disk used to save containerd user data 7 | // 8 | //go:generate mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_disk_disk.go -package=mocks -mock_names UserDataDiskManager=UserDataDiskManager,diskFS=MockdiskFS -source=disk.go . 9 | package disk 10 | 11 | import ( 12 | "github.com/spf13/afero" 13 | 14 | "github.com/runfinch/finch/pkg/command" 15 | "github.com/runfinch/finch/pkg/config" 16 | "github.com/runfinch/finch/pkg/flog" 17 | fpath "github.com/runfinch/finch/pkg/path" 18 | ) 19 | 20 | // UserDataDiskManager is used to check the user data disk configuration and create it if needed. 21 | type UserDataDiskManager interface { 22 | EnsureUserDataDisk() error 23 | DetachUserDataDisk() error 24 | } 25 | 26 | // fs functions required for setting up the user data disk. 27 | type diskFS interface { 28 | afero.Fs 29 | afero.Linker 30 | afero.LinkReader 31 | } 32 | 33 | type userDataDiskManager struct { 34 | ncc command.NerdctlCmdCreator 35 | ecc command.Creator 36 | fs diskFS 37 | finch fpath.Finch 38 | rootDir string 39 | config *config.Finch 40 | logger flog.Logger 41 | } 42 | 43 | // NewUserDataDiskManager is a constructor for UserDataDiskManager. 44 | func NewUserDataDiskManager( 45 | ncc command.NerdctlCmdCreator, 46 | ecc command.Creator, 47 | fs diskFS, 48 | finch fpath.Finch, 49 | rootDir string, 50 | config *config.Finch, 51 | logger flog.Logger, 52 | ) UserDataDiskManager { 53 | return &userDataDiskManager{ 54 | ncc: ncc, 55 | ecc: ecc, 56 | fs: fs, 57 | finch: finch, 58 | rootDir: rootDir, 59 | config: config, 60 | logger: logger, 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /pkg/mocks/lima_wrapper.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: github.com/runfinch/finch/pkg/lima/wrapper (interfaces: LimaWrapper) 3 | // 4 | // Generated by this command: 5 | // 6 | // mockgen --destination=../../mocks/lima_wrapper.go -package=mocks github.com/runfinch/finch/pkg/lima/wrapper LimaWrapper 7 | // 8 | 9 | // Package mocks is a generated GoMock package. 10 | package mocks 11 | 12 | import ( 13 | user "os/user" 14 | reflect "reflect" 15 | 16 | gomock "go.uber.org/mock/gomock" 17 | ) 18 | 19 | // MockLimaWrapper is a mock of LimaWrapper interface. 20 | type MockLimaWrapper struct { 21 | ctrl *gomock.Controller 22 | recorder *MockLimaWrapperMockRecorder 23 | isgomock struct{} 24 | } 25 | 26 | // MockLimaWrapperMockRecorder is the mock recorder for MockLimaWrapper. 27 | type MockLimaWrapperMockRecorder struct { 28 | mock *MockLimaWrapper 29 | } 30 | 31 | // NewMockLimaWrapper creates a new mock instance. 32 | func NewMockLimaWrapper(ctrl *gomock.Controller) *MockLimaWrapper { 33 | mock := &MockLimaWrapper{ctrl: ctrl} 34 | mock.recorder = &MockLimaWrapperMockRecorder{mock} 35 | return mock 36 | } 37 | 38 | // EXPECT returns an object that allows the caller to indicate expected use. 39 | func (m *MockLimaWrapper) EXPECT() *MockLimaWrapperMockRecorder { 40 | return m.recorder 41 | } 42 | 43 | // LimaUser mocks base method. 44 | func (m *MockLimaWrapper) LimaUser(warn bool) *user.User { 45 | m.ctrl.T.Helper() 46 | ret := m.ctrl.Call(m, "LimaUser", warn) 47 | ret0, _ := ret[0].(*user.User) 48 | return ret0 49 | } 50 | 51 | // LimaUser indicates an expected call of LimaUser. 52 | func (mr *MockLimaWrapperMockRecorder) LimaUser(warn any) *gomock.Call { 53 | mr.mock.ctrl.T.Helper() 54 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LimaUser", reflect.TypeOf((*MockLimaWrapper)(nil).LimaUser), warn) 55 | } 56 | -------------------------------------------------------------------------------- /e2e/vm/install_windows_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build windows 5 | 6 | package vm 7 | 8 | import ( 9 | "fmt" 10 | "os" 11 | "os/exec" 12 | 13 | "github.com/onsi/ginkgo/v2" 14 | "github.com/onsi/gomega" 15 | "github.com/runfinch/common-tests/option" 16 | ) 17 | 18 | func testMSIInstallPermission(_ *option.Option, installed bool) { 19 | finchInstallFolder := `C:\Program Files\Finch` 20 | finchBin := finchInstallFolder + `\bin\finch.exe` 21 | ginkgo.Describe("The Finch Installer", func() { 22 | ginkgo.BeforeEach(func() { 23 | if !installed { 24 | ginkgo.Skip("install permissions are only checked on the installed MSI") 25 | } 26 | }) 27 | ginkgo.It("should install finch at "+finchBin, func() { 28 | _, err := os.Stat(finchBin) 29 | gomega.Expect(err).Should(gomega.BeNil()) 30 | }) 31 | ginkgo.DescribeTable("should verify permissions", 32 | func(path string) { 33 | _, err := os.Stat(path) 34 | gomega.Expect(err).Should(gomega.BeNil()) 35 | path = fmt.Sprintf(`"%s"`, path) 36 | cmd := exec.Command("powershell", "-NoProfile", `.\install_windows_permission_check.ps1`, path) 37 | out, err := cmd.CombinedOutput() 38 | // Verify that there are no explicit permissions meaning we rely on inherited permissions. 39 | // Note: this checks the output before checking the error because if there is a failure, the 40 | // output will contain the error information and the error itself will be effectively "exit status 1". 41 | gomega.Expect(string(out)).Should(gomega.BeEmpty()) 42 | gomega.Expect(err).Should(gomega.BeNil()) 43 | }, 44 | ginkgo.Entry("when the path is the install folder", finchInstallFolder), 45 | ginkgo.Entry("when the path is the finch binary", finchBin), 46 | ) 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /installer-builder/darwin/distribution.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Finch 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | Finch.pkg 36 | 37 | -------------------------------------------------------------------------------- /e2e/vm/vm_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package vm 7 | 8 | import ( 9 | "runtime" 10 | "time" 11 | 12 | "github.com/onsi/ginkgo/v2" 13 | "github.com/onsi/gomega" 14 | "github.com/runfinch/common-tests/command" 15 | "github.com/runfinch/common-tests/option" 16 | ) 17 | 18 | const ( 19 | virtualMachineRootCmd = "vm" 20 | ) 21 | 22 | var resetVM = func(o *option.Option) { 23 | origFinchCfg := readFile(finchConfigFilePath) 24 | 25 | command.New(o, virtualMachineRootCmd, "stop", "-f").WithoutCheckingExitCode().WithTimeoutInSeconds(20).Run() 26 | time.Sleep(1 * time.Second) 27 | command.New(o, virtualMachineRootCmd, "remove", "-f").WithoutCheckingExitCode().WithTimeoutInSeconds(10).Run() 28 | time.Sleep(1 * time.Second) 29 | if runtime.GOOS == "windows" { 30 | // clean up iptables 31 | //nolint:lll // link to explanation 32 | // https://docs.rancherdesktop.io/troubleshooting-tips/#q-how-do-i-fix-fata0005-subnet-1040024-overlaps-with-other-one-on-this-address-space-when-running-a-container-using-nerdctl-run 33 | gomega.Expect(shutdownWSL()).Should(gomega.BeNil()) 34 | } 35 | 36 | ginkgo.DeferCleanup(func() { 37 | writeFile(finchConfigFilePath, origFinchCfg) 38 | command.New(o, virtualMachineRootCmd, "stop", "-f").WithoutCheckingExitCode().WithTimeoutInSeconds(20).Run() 39 | time.Sleep(1 * time.Second) 40 | command.New(o, virtualMachineRootCmd, "remove", "-f").WithoutCheckingExitCode().WithTimeoutInSeconds(10).Run() 41 | time.Sleep(1 * time.Second) 42 | if runtime.GOOS == "windows" { 43 | gomega.Expect(shutdownWSL()).Should(gomega.BeNil()) 44 | } 45 | time.Sleep(1 * time.Second) 46 | command.New(o, virtualMachineRootCmd, "init").WithoutCheckingExitCode().WithTimeoutInSeconds(160).Run() 47 | }) 48 | } 49 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | enable: 4 | - copyloopvar 5 | - errname 6 | - errorlint 7 | - forcetypeassert 8 | - gocritic 9 | - godot 10 | - goheader 11 | - gosec 12 | - lll 13 | - makezero 14 | - misspell 15 | - nilerr 16 | - nilnil 17 | - nolintlint 18 | - nosprintfhostport 19 | - paralleltest 20 | - predeclared 21 | - reassign 22 | - revive 23 | - staticcheck 24 | - testableexamples 25 | - unconvert 26 | - unparam 27 | - usestdlibvars 28 | - wastedassign 29 | - whitespace 30 | settings: 31 | goheader: 32 | template-path: copyright_header 33 | gosec: 34 | config: 35 | G306: "0o644" 36 | lll: 37 | # 145 is just a lax value that does not require too much work to add this check, 38 | # and we don't want this to be too strict anyway. 39 | line-length: 145 40 | tab-width: 4 41 | makezero: 42 | always: true 43 | nolintlint: 44 | require-explanation: true 45 | require-specific: true 46 | staticcheck: 47 | checks: 48 | # ST1003 is left out because it is a bit opinionated. 49 | - -ST1003 50 | - all 51 | exclusions: 52 | generated: lax 53 | rules: 54 | - linters: 55 | - lll 56 | # A go:generate statement has to be in the same line: https://github.com/golang/go/issues/46050. 57 | source: '^//go:generate ' 58 | paths: 59 | - third_party$ 60 | - builtin$ 61 | - examples$ 62 | issues: 63 | fix: true 64 | formatters: 65 | enable: 66 | - gofumpt 67 | - goimports 68 | settings: 69 | goimports: 70 | local-prefixes: 71 | - github.com/runfinch/finch 72 | exclusions: 73 | generated: lax 74 | paths: 75 | - third_party$ 76 | - builtin$ 77 | - examples$ 78 | -------------------------------------------------------------------------------- /cmd/finch/nerdctl_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package main 7 | 8 | import ( 9 | "fmt" 10 | "strings" 11 | 12 | dockerops "github.com/docker/docker/opts" 13 | "github.com/lima-vm/lima/pkg/networks" 14 | 15 | "github.com/runfinch/finch/pkg/command" 16 | "github.com/runfinch/finch/pkg/flog" 17 | ) 18 | 19 | func convertToWSLPath(_ NerdctlCommandSystemDeps, _ string) (string, error) { 20 | return "", nil 21 | } 22 | 23 | var osAliasMap = map[string]string{} 24 | 25 | var osArgHandlerMap = map[string]map[string]argHandler{} 26 | 27 | var osCommandHandlerMap = map[string]commandHandler{} 28 | 29 | func (nc *nerdctlCommand) GetCmdArgs() []string { 30 | return []string{"shell", limaInstanceName, "sudo", "-E"} 31 | } 32 | 33 | func resolveIP(host string, logger flog.Logger, _ command.Creator) (string, error) { 34 | parts := strings.SplitN(host, ":", 2) 35 | // If the IP Address is a string called "host-gateway", replace this value with the IP address that can be used to 36 | // access host from the containers. 37 | // TODO: make the host gateway ip configurable. 38 | var resolvedIP string 39 | if parts[1] == dockerops.HostGatewayName { 40 | resolvedIP = networks.SlirpGateway 41 | 42 | logger.Debugf(`Resolving special IP "host-gateway" to %q for host %q`, resolvedIP, parts[0]) 43 | return fmt.Sprintf("%s:%s", parts[0], resolvedIP), nil 44 | } 45 | return host, nil 46 | } 47 | 48 | func handleBindMountPath(_ NerdctlCommandSystemDeps, _ map[string]string) error { 49 | // Do nothing by default 50 | return nil 51 | } 52 | 53 | func mapToString(m map[string]string) string { 54 | var parts []string 55 | for k, v := range m { 56 | part := fmt.Sprintf("%s=%s", k, v) 57 | parts = append(parts, part) 58 | } 59 | return strings.Join(parts, ",") 60 | } 61 | -------------------------------------------------------------------------------- /coverage/coverage.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package main for unit test coverage parsing 5 | package main 6 | 7 | import ( 8 | "bufio" 9 | "fmt" 10 | "math" 11 | "os" 12 | "os/exec" 13 | "strconv" 14 | "strings" 15 | ) 16 | 17 | func main() { 18 | threshold := 100.0 19 | if len(os.Args) > 1 { 20 | argThreshold, err := strconv.ParseFloat(os.Args[1], 64) 21 | if err != nil { 22 | fmt.Fprintln(os.Stderr, "Invalid threshold value. Please provide a number.") 23 | os.Exit(1) 24 | } 25 | threshold = argThreshold 26 | } 27 | 28 | cmd := exec.Command("go", "tool", "cover", "-func=coverage.out") 29 | output, err := cmd.Output() 30 | if err != nil { 31 | fmt.Fprintln(os.Stderr, "Error executing coverage command:", err) 32 | os.Exit(1) 33 | } 34 | 35 | var coverage float64 36 | scanner := bufio.NewScanner(strings.NewReader(string(output))) 37 | for scanner.Scan() { 38 | line := scanner.Text() 39 | if strings.Contains(line, "total:") { 40 | parts := strings.Fields(line) 41 | if len(parts) > 2 { 42 | coverageStr := strings.TrimSuffix(parts[2], "%") 43 | coverage, err = strconv.ParseFloat(coverageStr, 64) 44 | if err != nil { 45 | fmt.Fprintln(os.Stderr, "Error parsing coverage:", err) 46 | os.Exit(1) 47 | } 48 | coverage = math.Round(coverage) 49 | fmt.Printf("Total Coverage: %.0f%%\n", coverage) 50 | break 51 | } 52 | } 53 | } 54 | 55 | if err := scanner.Err(); err != nil { 56 | fmt.Fprintln(os.Stderr, "Error reading coverage output:", err) 57 | os.Exit(1) 58 | } 59 | 60 | if coverage < threshold { 61 | fmt.Fprintf(os.Stderr, "Coverage %.0f%% is below the %.0f%% threshold\n", coverage, threshold) 62 | os.Exit(1) 63 | } 64 | 65 | fmt.Printf("Coverage %.0f%% meets the %.0f%% threshold\n", coverage, threshold) 66 | } 67 | -------------------------------------------------------------------------------- /winres/winres.json: -------------------------------------------------------------------------------- 1 | { 2 | "RT_GROUP_ICON": { 3 | "APP": { 4 | "0000": "./../msi-builder/finch.ico" 5 | } 6 | }, 7 | "RT_MANIFEST": { 8 | "#1": { 9 | "0409": { 10 | "identity": { 11 | "name": "", 12 | "version": "" 13 | }, 14 | "description": "An open source client for container development", 15 | "minimum-os": "win10", 16 | "execution-level": "", 17 | "ui-access": false, 18 | "auto-elevate": false, 19 | "dpi-awareness": "system", 20 | "disable-theming": false, 21 | "disable-window-filtering": false, 22 | "high-resolution-scrolling-aware": false, 23 | "ultra-high-resolution-scrolling-aware": false, 24 | "long-path-aware": false, 25 | "printer-driver-isolation": false, 26 | "gdi-scaling": false, 27 | "segment-heap": false, 28 | "use-common-controls-v6": false 29 | } 30 | } 31 | }, 32 | "RT_VERSION": { 33 | "#1": { 34 | "0000": { 35 | "fixed": { 36 | "file_version": "0.0.0.0", 37 | "product_version": "0.0.0.0" 38 | }, 39 | "info": { 40 | "0409": { 41 | "Comments": "", 42 | "CompanyName": "RunFinch", 43 | "FileDescription": "Finch", 44 | "FileVersion": "", 45 | "InternalName": "runfinch/finch", 46 | "LegalCopyright": "Amazon.com, Inc. or its affiliates. All Rights Reserved", 47 | "LegalTrademarks": "", 48 | "OriginalFilename": "finch.exe", 49 | "PrivateBuild": "", 50 | "ProductName": "Finch", 51 | "ProductVersion": "", 52 | "SpecialBuild": "" 53 | } 54 | } 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /docs/debug.md: -------------------------------------------------------------------------------- 1 | # Debug 2 | 3 | Below are common scenarios users might encounter for Finch. 4 | 5 | ## General 6 | 7 | ### How to shell into the VM? 8 | 9 | Linux versions of Finch do not use a VM. 10 | 11 | #### macOS 12 | 13 | ```sh 14 | LIMA_HOME=/Applications/Finch/lima/data /Applications/Finch/lima/bin/limactl shell finch 15 | ``` 16 | 17 | #### Windows 18 | 19 | ```sh 20 | wsl -d lima-finch 21 | ``` 22 | 23 | ## MacOS 24 | 25 | ### I see repeated pull/build failures with errors suggesting space is insufficient 26 | 27 | This likely means that the finch vm is out of space and we are not able to pull the image even if we have other things correctly working. This can be verified by the following commands: 28 | 29 | ```bash 30 | LIMA_HOME=/Applications/Finch/lima/data /Applications/Finch/lima/bin/limactl shell finch df -h | grep -i vdb1 31 | 32 | /dev/vdb1 59G 25G 32G 44% /mnt/lima-finch 33 | ``` 34 | 35 | To fix this: 36 | 37 | ```bash 38 | # Shell into the vm: 39 | LIMA_HOME=/Applications/Finch/lima/data /Applications/Finch/lima/bin/limactl shell finch 40 | 41 | # Clean up the leases: 42 | sudo ctr leases rm $(sudo ctr leases ls | grep flat | awk '{print $1}') 43 | ``` 44 | 45 | The above steps will help you to clean up the disk for finch to use, but when you check your disk space it might still say that your vm is occupying a large disk space. Run the following command to reclaim those 46 | 47 | ```bash 48 | # Shell into the vm: 49 | LIMA_HOME=/Applications/Finch/lima/data /Applications/Finch/lima/bin/limactl shell finch 50 | 51 | # Run fstrim: 52 | sudo fstrim -v /mnt/lima-finch 53 | ``` 54 | 55 | ### Pulling an image returns an error like `error getting credentials - err: exec: "docker-credential-osxkeychain": executable file not found in $PATH, out: `` ` 56 | 57 | This can usually be fixed by adding `config.json` to your `~/.finch` directory, and populating its contents with an empty json (`{}`) 58 | -------------------------------------------------------------------------------- /pkg/mocks/pkg_config_load_system_deps.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Code generated by MockGen. DO NOT EDIT. 5 | // Source: github.com/runfinch/finch/pkg/config (interfaces: LoadSystemDeps) 6 | // 7 | // Generated by this command: 8 | // 9 | // mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_config_load_system_deps.go -package=mocks -mock_names LoadSystemDeps=LoadSystemDeps . LoadSystemDeps 10 | // 11 | 12 | // Package mocks is a generated GoMock package. 13 | package mocks 14 | 15 | import ( 16 | reflect "reflect" 17 | 18 | gomock "go.uber.org/mock/gomock" 19 | ) 20 | 21 | // LoadSystemDeps is a mock of LoadSystemDeps interface. 22 | type LoadSystemDeps struct { 23 | ctrl *gomock.Controller 24 | recorder *LoadSystemDepsMockRecorder 25 | isgomock struct{} 26 | } 27 | 28 | // LoadSystemDepsMockRecorder is the mock recorder for LoadSystemDeps. 29 | type LoadSystemDepsMockRecorder struct { 30 | mock *LoadSystemDeps 31 | } 32 | 33 | // NewLoadSystemDeps creates a new mock instance. 34 | func NewLoadSystemDeps(ctrl *gomock.Controller) *LoadSystemDeps { 35 | mock := &LoadSystemDeps{ctrl: ctrl} 36 | mock.recorder = &LoadSystemDepsMockRecorder{mock} 37 | return mock 38 | } 39 | 40 | // EXPECT returns an object that allows the caller to indicate expected use. 41 | func (m *LoadSystemDeps) EXPECT() *LoadSystemDepsMockRecorder { 42 | return m.recorder 43 | } 44 | 45 | // NumCPU mocks base method. 46 | func (m *LoadSystemDeps) NumCPU() int { 47 | m.ctrl.T.Helper() 48 | ret := m.ctrl.Call(m, "NumCPU") 49 | ret0, _ := ret[0].(int) 50 | return ret0 51 | } 52 | 53 | // NumCPU indicates an expected call of NumCPU. 54 | func (mr *LoadSystemDepsMockRecorder) NumCPU() *gomock.Call { 55 | mr.mock.ctrl.T.Helper() 56 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NumCPU", reflect.TypeOf((*LoadSystemDeps)(nil).NumCPU)) 57 | } 58 | -------------------------------------------------------------------------------- /pkg/mocks/pkg_ssh_dialer.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Code generated by MockGen. DO NOT EDIT. 5 | // Source: github.com/runfinch/finch/pkg/fssh (interfaces: Dialer) 6 | // 7 | // Generated by this command: 8 | // 9 | // mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_ssh_dialer.go -package=mocks -mock_names Dialer=Dialer . Dialer 10 | // 11 | 12 | // Package mocks is a generated GoMock package. 13 | package mocks 14 | 15 | import ( 16 | reflect "reflect" 17 | 18 | gomock "go.uber.org/mock/gomock" 19 | ssh "golang.org/x/crypto/ssh" 20 | ) 21 | 22 | // Dialer is a mock of Dialer interface. 23 | type Dialer struct { 24 | ctrl *gomock.Controller 25 | recorder *DialerMockRecorder 26 | isgomock struct{} 27 | } 28 | 29 | // DialerMockRecorder is the mock recorder for Dialer. 30 | type DialerMockRecorder struct { 31 | mock *Dialer 32 | } 33 | 34 | // NewDialer creates a new mock instance. 35 | func NewDialer(ctrl *gomock.Controller) *Dialer { 36 | mock := &Dialer{ctrl: ctrl} 37 | mock.recorder = &DialerMockRecorder{mock} 38 | return mock 39 | } 40 | 41 | // EXPECT returns an object that allows the caller to indicate expected use. 42 | func (m *Dialer) EXPECT() *DialerMockRecorder { 43 | return m.recorder 44 | } 45 | 46 | // Dial mocks base method. 47 | func (m *Dialer) Dial(network, addr string, config *ssh.ClientConfig) (*ssh.Client, error) { 48 | m.ctrl.T.Helper() 49 | ret := m.ctrl.Call(m, "Dial", network, addr, config) 50 | ret0, _ := ret[0].(*ssh.Client) 51 | ret1, _ := ret[1].(error) 52 | return ret0, ret1 53 | } 54 | 55 | // Dial indicates an expected call of Dial. 56 | func (mr *DialerMockRecorder) Dial(network, addr, config any) *gomock.Call { 57 | mr.mock.ctrl.T.Helper() 58 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Dial", reflect.TypeOf((*Dialer)(nil).Dial), network, addr, config) 59 | } 60 | -------------------------------------------------------------------------------- /pkg/mocks/pkg_support.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Code generated by MockGen. DO NOT EDIT. 5 | // Source: github.com/runfinch/finch/pkg/support (interfaces: SystemDeps) 6 | // 7 | // Generated by this command: 8 | // 9 | // mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_support.go -package=mocks -mock_names SystemDeps=SupportSystemDeps . SystemDeps 10 | // 11 | 12 | // Package mocks is a generated GoMock package. 13 | package mocks 14 | 15 | import ( 16 | reflect "reflect" 17 | 18 | gomock "go.uber.org/mock/gomock" 19 | ) 20 | 21 | // SupportSystemDeps is a mock of SystemDeps interface. 22 | type SupportSystemDeps struct { 23 | ctrl *gomock.Controller 24 | recorder *SupportSystemDepsMockRecorder 25 | isgomock struct{} 26 | } 27 | 28 | // SupportSystemDepsMockRecorder is the mock recorder for SupportSystemDeps. 29 | type SupportSystemDepsMockRecorder struct { 30 | mock *SupportSystemDeps 31 | } 32 | 33 | // NewSupportSystemDeps creates a new mock instance. 34 | func NewSupportSystemDeps(ctrl *gomock.Controller) *SupportSystemDeps { 35 | mock := &SupportSystemDeps{ctrl: ctrl} 36 | mock.recorder = &SupportSystemDepsMockRecorder{mock} 37 | return mock 38 | } 39 | 40 | // EXPECT returns an object that allows the caller to indicate expected use. 41 | func (m *SupportSystemDeps) EXPECT() *SupportSystemDepsMockRecorder { 42 | return m.recorder 43 | } 44 | 45 | // Executable mocks base method. 46 | func (m *SupportSystemDeps) Executable() (string, error) { 47 | m.ctrl.T.Helper() 48 | ret := m.ctrl.Call(m, "Executable") 49 | ret0, _ := ret[0].(string) 50 | ret1, _ := ret[1].(error) 51 | return ret0, ret1 52 | } 53 | 54 | // Executable indicates an expected call of Executable. 55 | func (mr *SupportSystemDepsMockRecorder) Executable() *gomock.Call { 56 | mr.mock.ctrl.T.Helper() 57 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Executable", reflect.TypeOf((*SupportSystemDeps)(nil).Executable)) 58 | } 59 | -------------------------------------------------------------------------------- /docs/cmd/finch_build.md: -------------------------------------------------------------------------------- 1 | # finch build 2 | 3 | Build an image from a Dockerfile. Needs buildkitd to be running. 4 | If Dockerfile is not present and -f is not specified, it will look for Containerfile and build with it. 5 | 6 | ```text 7 | finch build [flags] PATH 8 | ``` 9 | 10 | ## Options 11 | 12 | ```text 13 | --build-arg stringArray Set build-time variables 14 | --buildkit-host string BuildKit address [$BUILDKIT_HOST] (default "unix:///run/buildkit/buildkitd.sock") 15 | --cache-from stringArray External cache sources (eg. user/app:cache, type=local,src=path/to/dir) 16 | --cache-to stringArray Cache export destinations (eg. user/app:cache, type=local,dest=path/to/dir) 17 | -f, --file string Name of the Dockerfile 18 | -h, --help help for build 19 | --iidfile string Write the image ID to the file 20 | --label stringArray Set metadata for an image 21 | --network string Set type of network for build (format:network=default|none|host) (default "default") 22 | --no-cache Do not use cache when building the image 23 | -o, --output string Output destination (format: type=local,dest=path) 24 | --platform strings Set target platform for build (e.g., "amd64", "arm64") 25 | --progress string Set type of progress output (auto, plain, tty). Use plain to show container output (default "auto") 26 | -q, --quiet Suppress the build output and print image ID on success 27 | --rm Remove intermediate containers after a successful build (default true) 28 | --secret stringArray Secret file to expose to the build: id=mysecret,src=/local/secret 29 | --ssh stringArray SSH agent socket or keys to expose to the build (format: default|[=|[,]]) 30 | -t, --tag stringArray Name and optionally a tag in the 'name:tag' format 31 | --target string Set the target build stage to build 32 | ``` 33 | -------------------------------------------------------------------------------- /cmd/finch/virtual_machine_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package main 7 | 8 | import ( 9 | "os" 10 | 11 | "github.com/spf13/afero" 12 | "github.com/spf13/cobra" 13 | 14 | "github.com/runfinch/finch/pkg/command" 15 | "github.com/runfinch/finch/pkg/config" 16 | "github.com/runfinch/finch/pkg/dependency" 17 | "github.com/runfinch/finch/pkg/disk" 18 | "github.com/runfinch/finch/pkg/flog" 19 | "github.com/runfinch/finch/pkg/path" 20 | ) 21 | 22 | func newDiskVMCommand(creator command.NerdctlCmdCreator, logger flog.Logger) *cobra.Command { 23 | diskCmd := &cobra.Command{ 24 | Use: "disk", 25 | Short: "Manage virtual machine disk operations", 26 | } 27 | 28 | diskCmd.AddCommand( 29 | newVMDiskResizeCommand(creator, logger), 30 | newVMDiskInfoCommand(creator, logger), 31 | ) 32 | 33 | return diskCmd 34 | } 35 | 36 | func newVirtualMachineCommand( 37 | limaCmdCreator command.NerdctlCmdCreator, 38 | logger flog.Logger, 39 | optionalDepGroups []*dependency.Group, 40 | lca config.LimaConfigApplier, 41 | nca config.NerdctlConfigApplier, 42 | fp path.Finch, 43 | fs afero.Fs, 44 | diskManager disk.UserDataDiskManager, 45 | ) *cobra.Command { 46 | virtualMachineCommand := &cobra.Command{ 47 | Use: virtualMachineRootCmd, 48 | Short: "Manage the virtual machine lifecycle", 49 | } 50 | 51 | virtualMachineCommand.AddCommand( 52 | newStartVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fs, fp.LimaSSHPrivateKeyPath(), diskManager), 53 | newStopVMCommand(limaCmdCreator, diskManager, logger), 54 | newRemoveVMCommand(limaCmdCreator, diskManager, logger), 55 | newStatusVMCommand(limaCmdCreator, logger, os.Stdout), 56 | newInitVMCommand(limaCmdCreator, logger, optionalDepGroups, lca, nca, fp.BaseYamlFilePath(), fs, 57 | fp.LimaSSHPrivateKeyPath(), diskManager), 58 | newSettingsVMCommand(logger, lca, fs, os.Stdout), 59 | newDiskVMCommand(limaCmdCreator, logger), 60 | ) 61 | 62 | return virtualMachineCommand 63 | } 64 | -------------------------------------------------------------------------------- /pkg/config/defaults_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package config 7 | 8 | import ( 9 | "math" 10 | 11 | "github.com/docker/go-units" 12 | "github.com/xorcare/pointer" 13 | 14 | "github.com/runfinch/finch/pkg/command" 15 | "github.com/runfinch/finch/pkg/fmemory" 16 | ) 17 | 18 | const ( 19 | // 2,147,483,648 => 2GiB. 20 | fallbackMemory float64 = 2_147_483_648 21 | fallbackCPUs int = 2 22 | ) 23 | 24 | func vmDefault(cfg *Finch, supportsVz bool) { 25 | if cfg.VMType == nil { 26 | if supportsVz { 27 | cfg.VMType = pointer.String("vz") 28 | } else { 29 | cfg.VMType = pointer.String("qemu") 30 | } 31 | } 32 | } 33 | 34 | func rosettaDefault(cfg *Finch) { 35 | if cfg.Rosetta == nil { 36 | cfg.Rosetta = pointer.Bool(false) 37 | } 38 | } 39 | 40 | func memoryDefault(cfg *Finch, mem fmemory.Memory) { 41 | if cfg.Memory == nil { 42 | defaultMemory := math.Round(float64(mem.TotalMemory()) * 0.5) 43 | if defaultMemory >= fallbackMemory { 44 | cfg.Memory = pointer.String(units.BytesSize(defaultMemory)) 45 | } else { 46 | cfg.Memory = pointer.String(units.BytesSize(fallbackMemory)) 47 | } 48 | } 49 | } 50 | 51 | func cpuDefault(cfg *Finch, deps LoadSystemDeps) { 52 | if cfg.CPUs == nil { 53 | defaultCPUs := int(math.Round(float64(deps.NumCPU()) * 0.5)) 54 | if defaultCPUs >= fallbackCPUs { 55 | cfg.CPUs = pointer.Int(defaultCPUs) 56 | } else { 57 | cfg.CPUs = pointer.Int(fallbackCPUs) 58 | } 59 | } 60 | } 61 | 62 | // applyDefaults sets default configuration options if they are not already set. 63 | func applyDefaults( 64 | cfg *Finch, 65 | deps LoadSystemDeps, 66 | mem fmemory.Memory, 67 | ecc command.Creator, 68 | ) *Finch { 69 | cpuDefault(cfg, deps) 70 | memoryDefault(cfg, mem) 71 | supportsVz := false 72 | vz, err := SupportsVirtualizationFramework(ecc) 73 | if err == nil && vz { 74 | supportsVz = true 75 | } 76 | vmDefault(cfg, supportsVz) 77 | rosettaDefault(cfg) 78 | 79 | return cfg 80 | } 81 | -------------------------------------------------------------------------------- /pkg/flog/log.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package flog contains logging-related APIs. 5 | package flog 6 | 7 | // Logger should be used to write any logs. No concrete implementations should be directly used. 8 | // 9 | //go:generate mockgen -copyright_file=../../copyright_header -destination=../mocks/logger.go -package=mocks -mock_names Logger=Logger . Logger 10 | type Logger interface { 11 | Debugf(format string, args ...interface{}) 12 | Debugln(args ...interface{}) 13 | Info(args ...interface{}) 14 | Infof(format string, args ...interface{}) 15 | Infoln(args ...interface{}) 16 | Warnln(args ...interface{}) 17 | Warnf(format string, args ...interface{}) 18 | Error(args ...interface{}) 19 | Errorf(format string, args ...interface{}) 20 | Fatal(args ...interface{}) 21 | SetLevel(level Level) 22 | SetFormatter(formatter Formatter) 23 | } 24 | 25 | // Log defines the properties of every log message. 26 | type Log struct { 27 | Level string `json:"level,omitempty"` 28 | Message string `json:"msg,omitempty"` 29 | Time string `json:"time,omitempty"` 30 | } 31 | 32 | // Level denotes a log level. Check the constants below for more information. 33 | type Level int 34 | 35 | //go:generate stringer -type=Level 36 | const ( 37 | // Debug is the lowest log level. It should be used for debugging purposes. 38 | Debug Level = iota 39 | 40 | // Panic is the highest log level. It should be used for panic situations. 41 | // It will cause the program to panic and exit. 42 | Panic 43 | ) 44 | 45 | // Formatter denotes a log formatter. Check the constants below for more information. 46 | type Formatter int 47 | 48 | //go:generate stringer -type=Formatter 49 | const ( 50 | // Text is the default log formatter. It formats logs into text. 51 | Text Formatter = iota 52 | 53 | // TextWithoutTruncation is text log formatting with truncation of level text disabled. 54 | TextWithoutTruncation 55 | 56 | // JSON is the JSON log formatter. 57 | // It will also add a timestamp to the log message. 58 | JSON 59 | ) 60 | -------------------------------------------------------------------------------- /docs/cmd/finch_compose.md: -------------------------------------------------------------------------------- 1 | # finch compose 2 | 3 | Compose 4 | 5 | ```text 6 | finch compose [flags] COMMAND 7 | ``` 8 | 9 | ## Commands 10 | 11 | ```text 12 | build Build or rebuild services 13 | config Validate and view the Compose file 14 | cp Copy files/folders between a service container and the local filesystem 15 | create Creates containers for one or more services 16 | down Remove containers and associated resources 17 | exec Execute a command in a running container of the service 18 | images List images used by created containers in services 19 | kill Force stop service containers 20 | logs Show logs of running containers 21 | pause Pause all processes within containers of service(s). They can be unpaused with finch compose unpause 22 | port Print the public port for a port binding 23 | ps List containers of services 24 | pull Pull service images 25 | push Push service images 26 | restart Restart containers of given (or all) services 27 | rm Remove stopped service containers 28 | run Run a one-off command on a service 29 | start Start existing containers for service(s) 30 | stop Stop running containers without removing them. 31 | top Display the running processes of service containers 32 | unpause Unpause all processes within containers of service(s). 33 | up Create and start containers 34 | version Show the Compose version information 35 | ``` 36 | 37 | ## Options 38 | 39 | ```text 40 | --env-file string Specify an alternate environment file 41 | -f, --f stringArray Alias of --file 42 | --file stringArray Specify an alternate compose file 43 | -h, --help help for compose 44 | --ipfs-address string multiaddr of IPFS API (default uses $IPFS_PATH env variable if defined or local directory ~/.ipfs) 45 | --profile stringArray Specify a profile to enable 46 | --project-directory string Specify an alternate working directory 47 | -p, --project-name string Specify an alternate project name 48 | ``` 49 | -------------------------------------------------------------------------------- /pkg/mocks/pkg_config_nerdctl_config_applier.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Code generated by MockGen. DO NOT EDIT. 5 | // Source: github.com/runfinch/finch/pkg/config (interfaces: NerdctlConfigApplier) 6 | // 7 | // Generated by this command: 8 | // 9 | // mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_config_nerdctl_config_applier.go -package=mocks -mock_names NerdctlConfigApplier=NerdctlConfigApplier . NerdctlConfigApplier 10 | // 11 | 12 | // Package mocks is a generated GoMock package. 13 | package mocks 14 | 15 | import ( 16 | reflect "reflect" 17 | 18 | gomock "go.uber.org/mock/gomock" 19 | ) 20 | 21 | // NerdctlConfigApplier is a mock of NerdctlConfigApplier interface. 22 | type NerdctlConfigApplier struct { 23 | ctrl *gomock.Controller 24 | recorder *NerdctlConfigApplierMockRecorder 25 | isgomock struct{} 26 | } 27 | 28 | // NerdctlConfigApplierMockRecorder is the mock recorder for NerdctlConfigApplier. 29 | type NerdctlConfigApplierMockRecorder struct { 30 | mock *NerdctlConfigApplier 31 | } 32 | 33 | // NewNerdctlConfigApplier creates a new mock instance. 34 | func NewNerdctlConfigApplier(ctrl *gomock.Controller) *NerdctlConfigApplier { 35 | mock := &NerdctlConfigApplier{ctrl: ctrl} 36 | mock.recorder = &NerdctlConfigApplierMockRecorder{mock} 37 | return mock 38 | } 39 | 40 | // EXPECT returns an object that allows the caller to indicate expected use. 41 | func (m *NerdctlConfigApplier) EXPECT() *NerdctlConfigApplierMockRecorder { 42 | return m.recorder 43 | } 44 | 45 | // Apply mocks base method. 46 | func (m *NerdctlConfigApplier) Apply(remoteAddr string) error { 47 | m.ctrl.T.Helper() 48 | ret := m.ctrl.Call(m, "Apply", remoteAddr) 49 | ret0, _ := ret[0].(error) 50 | return ret0 51 | } 52 | 53 | // Apply indicates an expected call of Apply. 54 | func (mr *NerdctlConfigApplierMockRecorder) Apply(remoteAddr any) *gomock.Call { 55 | mr.mock.ctrl.T.Helper() 56 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Apply", reflect.TypeOf((*NerdctlConfigApplier)(nil).Apply), remoteAddr) 57 | } 58 | -------------------------------------------------------------------------------- /pkg/system/stdlib.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package system 5 | 6 | import ( 7 | "os" 8 | "path/filepath" 9 | "runtime" 10 | ) 11 | 12 | // StdLib implements the interfaces defined in system.go via standard library functions. 13 | type StdLib struct{} 14 | 15 | //revive:disable:exported The exported functions below are straightforward. 16 | 17 | func NewStdLib() *StdLib { 18 | return &StdLib{} 19 | } 20 | 21 | func (s *StdLib) EvalSymlinks(path string) (string, error) { 22 | return filepath.EvalSymlinks(path) 23 | } 24 | 25 | func (s *StdLib) FilePathJoin(elem ...string) string { 26 | return filepath.Join(elem...) 27 | } 28 | 29 | func (s *StdLib) Executable() (string, error) { 30 | return os.Executable() 31 | } 32 | 33 | func (s *StdLib) Environ() []string { 34 | return os.Environ() 35 | } 36 | 37 | func (s *StdLib) Env(key string) string { 38 | return os.Getenv(key) 39 | } 40 | 41 | func (s *StdLib) LookupEnv(key string) (string, bool) { 42 | return os.LookupEnv(key) 43 | } 44 | 45 | func (s *StdLib) Pipe() (*os.File, *os.File, error) { 46 | return os.Pipe() 47 | } 48 | 49 | func (s *StdLib) Stdin() *os.File { 50 | return os.Stdin 51 | } 52 | 53 | func (s *StdLib) Stdout() *os.File { 54 | return os.Stdout 55 | } 56 | 57 | func (s *StdLib) SetStdout(w *os.File) { 58 | os.Stdout = w 59 | } 60 | 61 | func (s *StdLib) Stderr() *os.File { 62 | return os.Stderr 63 | } 64 | 65 | func (s *StdLib) NumCPU() int { 66 | return runtime.NumCPU() 67 | } 68 | 69 | func (s *StdLib) ReadMemStats(st *runtime.MemStats) { 70 | runtime.ReadMemStats(st) 71 | } 72 | 73 | func (s *StdLib) Arch() string { 74 | return runtime.GOARCH 75 | } 76 | 77 | func (s *StdLib) OS() string { 78 | return runtime.GOOS 79 | } 80 | 81 | func (s *StdLib) GetUserHome() (string, error) { 82 | return os.UserHomeDir() 83 | } 84 | 85 | func (s *StdLib) GetWd() (string, error) { 86 | return os.Getwd() 87 | } 88 | 89 | func (s *StdLib) FilePathAbs(elem string) (string, error) { 90 | return filepath.Abs(elem) 91 | } 92 | 93 | func (s *StdLib) FilePathToSlash(elem string) string { 94 | return filepath.ToSlash(elem) 95 | } 96 | -------------------------------------------------------------------------------- /pkg/mocks/command_command_creator.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Code generated by MockGen. DO NOT EDIT. 5 | // Source: github.com/runfinch/finch/pkg/command (interfaces: Creator) 6 | // 7 | // Generated by this command: 8 | // 9 | // mockgen -copyright_file=../../copyright_header -destination=../mocks/command_command_creator.go -package=mocks -mock_names Creator=CommandCreator . Creator 10 | // 11 | 12 | // Package mocks is a generated GoMock package. 13 | package mocks 14 | 15 | import ( 16 | reflect "reflect" 17 | 18 | command "github.com/runfinch/finch/pkg/command" 19 | gomock "go.uber.org/mock/gomock" 20 | ) 21 | 22 | // CommandCreator is a mock of Creator interface. 23 | type CommandCreator struct { 24 | ctrl *gomock.Controller 25 | recorder *CommandCreatorMockRecorder 26 | isgomock struct{} 27 | } 28 | 29 | // CommandCreatorMockRecorder is the mock recorder for CommandCreator. 30 | type CommandCreatorMockRecorder struct { 31 | mock *CommandCreator 32 | } 33 | 34 | // NewCommandCreator creates a new mock instance. 35 | func NewCommandCreator(ctrl *gomock.Controller) *CommandCreator { 36 | mock := &CommandCreator{ctrl: ctrl} 37 | mock.recorder = &CommandCreatorMockRecorder{mock} 38 | return mock 39 | } 40 | 41 | // EXPECT returns an object that allows the caller to indicate expected use. 42 | func (m *CommandCreator) EXPECT() *CommandCreatorMockRecorder { 43 | return m.recorder 44 | } 45 | 46 | // Create mocks base method. 47 | func (m *CommandCreator) Create(name string, args ...string) command.Command { 48 | m.ctrl.T.Helper() 49 | varargs := []any{name} 50 | for _, a := range args { 51 | varargs = append(varargs, a) 52 | } 53 | ret := m.ctrl.Call(m, "Create", varargs...) 54 | ret0, _ := ret[0].(command.Command) 55 | return ret0 56 | } 57 | 58 | // Create indicates an expected call of Create. 59 | func (mr *CommandCreatorMockRecorder) Create(name any, args ...any) *gomock.Call { 60 | mr.mock.ctrl.T.Helper() 61 | varargs := append([]any{name}, args...) 62 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*CommandCreator)(nil).Create), varargs...) 63 | } 64 | -------------------------------------------------------------------------------- /installer-builder/tools/release-installer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -o errexit 3 | set -o pipefail 4 | 5 | source ./installer-builder/tools/artifact-helper.sh 6 | 7 | ARCH=${1} 8 | FINCH_VERSION=${2} 9 | INSTALLER_PRIVATE_BUCKET_NAME=${3} 10 | EXECUTABLE_BUCKET=${4} 11 | PKG_BUCKET=${5} 12 | NOTARIZATION_ACCOUNT=${6} 13 | NOTARIZATION_CREDENTIAL=${7} 14 | 15 | releaseInstaller() { 16 | echo "Finch-$FINCH_VERSION-$ARCH.pkg Installer Generation Started..." 17 | echo "[1/12] Clean Old Signing Artifact in S3 Buckets" 18 | cleanUpSigningArtifactInS3Buckets "$ARCH" "$EXECUTABLE_BUCKET" "$PKG_BUCKET" 19 | rm -rf "./installer-builder/output" 20 | mkdir -pv "./installer-builder/output" 21 | 22 | echo "[2/12] Get Original Finch Build" 23 | mkdir -pv "./installer-builder/output/origin" 24 | cp -RP ./_output "./installer-builder/output/origin" 25 | 26 | echo "[3/12] Extract Executables from Finch Build" 27 | bash ./installer-builder/tools/extract-executables.sh "$ARCH" 28 | 29 | echo "[4/12] Upload Unsigned Executables to S3 Buckets" 30 | uploadUnsignedExecutables "$ARCH" "$EXECUTABLE_BUCKET" 31 | 32 | echo "[5/12] Download Signed Executables from S3 Buckets" 33 | downloadSignedExecutables "$ARCH" "$EXECUTABLE_BUCKET" 34 | 35 | echo "[6/12] Merge Back Signed Executables to Finch Build" 36 | bash ./installer-builder/tools/merge-back-signed-executables.sh "$ARCH" 37 | 38 | echo "[7/12] Build .pkg" 39 | bash ./installer-builder/tools/build-macos-pkg.sh "$ARCH" "$FINCH_VERSION" 40 | 41 | echo "[8/12] Pack Unsigned .pkg" 42 | bash ./installer-builder/tools/pack-unsigned-pkg.sh "$ARCH" 43 | 44 | echo "[9/12] Upload Unsigned .pkg to S3 Buckets" 45 | uploadUnsignedPkg "$ARCH" "$PKG_BUCKET" 46 | 47 | echo "[10/12] Download Signed .pkg from S3 Buckets" 48 | downloadSignedPkg "$ARCH" "$PKG_BUCKET" 49 | 50 | echo "[11/12] App Store Notarization" 51 | bash ./installer-builder/tools/notarize.sh "$NOTARIZATION_ACCOUNT" "$NOTARIZATION_CREDENTIAL" 52 | 53 | echo "[12/12] Upload installer to S3 buckets" 54 | uploadNotarizedPkg "$ARCH" "$FINCH_VERSION" "$INSTALLER_PRIVATE_BUCKET_NAME" 55 | 56 | echo "Finch-$FINCH_VERSION-$ARCH.pkg Installer Generation Completed!" 57 | } 58 | 59 | releaseInstaller 60 | -------------------------------------------------------------------------------- /pkg/fssh/fssh.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // Package fssh provides functions and methods to configure and create SSH connections. 5 | package fssh 6 | 7 | import ( 8 | "errors" 9 | "fmt" 10 | "net" 11 | 12 | "github.com/spf13/afero" 13 | "golang.org/x/crypto/ssh" 14 | ) 15 | 16 | // Dialer abstracts out ssh.Dial to facilitate unit testing. 17 | // 18 | //go:generate mockgen -copyright_file=../../copyright_header -destination=../mocks/pkg_ssh_dialer.go -package=mocks -mock_names Dialer=Dialer . Dialer 19 | type Dialer interface { 20 | Dial(network string, addr string, config *ssh.ClientConfig) (*ssh.Client, error) 21 | } 22 | 23 | var _ Dialer = (*dialer)(nil) 24 | 25 | type dialer struct{} 26 | 27 | func (*dialer) Dial(network string, addr string, config *ssh.ClientConfig) (*ssh.Client, error) { 28 | return ssh.Dial(network, addr, config) 29 | } 30 | 31 | // NewDialer returns a Dialer that calls ssh.Dial under the hood. 32 | func NewDialer() Dialer { 33 | return &dialer{} 34 | } 35 | 36 | func hostKeyCallback() ssh.HostKeyCallback { 37 | return func(_ string, remote net.Addr, _ ssh.PublicKey) error { 38 | addr, ok := remote.(*net.TCPAddr) 39 | if !ok { 40 | return errors.New("failed to convert the remote address to a TCP address") 41 | } 42 | if !addr.IP.IsLoopback() { 43 | return fmt.Errorf("addresses that are not loopback addresses are not supported, address: %s", addr.String()) 44 | } 45 | return nil 46 | } 47 | } 48 | 49 | // NewClientConfig returns a client config that can only connect to a loopback address. 50 | func NewClientConfig(fs afero.Fs, user string, privateKeyPath string) (*ssh.ClientConfig, error) { 51 | fileBytes, err := afero.ReadFile(fs, privateKeyPath) 52 | if err != nil { 53 | return nil, fmt.Errorf("failed to open private key file: %w", err) 54 | } 55 | signer, err := ssh.ParsePrivateKey(fileBytes) 56 | if err != nil { 57 | return nil, fmt.Errorf("failed to parse private key from %s: %w", privateKeyPath, err) 58 | } 59 | 60 | auths := []ssh.AuthMethod{ssh.PublicKeys(signer)} 61 | 62 | return &ssh.ClientConfig{ 63 | User: user, 64 | Auth: auths, 65 | HostKeyCallback: hostKeyCallback(), 66 | }, nil 67 | } 68 | -------------------------------------------------------------------------------- /pkg/command/nerdctl_remote.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package command 7 | 8 | import ( 9 | "fmt" 10 | "io" 11 | 12 | "github.com/runfinch/finch/pkg/flog" 13 | ) 14 | 15 | // EnvKeyLimaHome is the name of the environment variable that Lima uses to set the "lima home" path. 16 | // This is exported to facilitate unit testing, since it uses a different package (command_test). 17 | const EnvKeyLimaHome = "LIMA_HOME" 18 | 19 | type nerdctlCmdCreator struct { 20 | cmdCreator Creator 21 | logger flog.Logger 22 | systemDeps NerdctlCmdCreatorSystemDeps 23 | limaHomePath string 24 | limactlPath string 25 | binPath string 26 | } 27 | 28 | // NewNerdctlCmdCreator returns a NerdctlCmdCreator that creates nerdctl commands. 29 | // In "remote" mode, it uses limactl commands, configured to use binaries at lima-related paths and then executes nerdctl. 30 | // In "native" mode, it directly executes nerdctl from the user's PATH. 31 | func NewNerdctlCmdCreator( 32 | cmdCreator Creator, 33 | logger flog.Logger, 34 | limaHomePath, 35 | limactlPath string, 36 | binPath string, 37 | systemDeps NerdctlCmdCreatorSystemDeps, 38 | ) NerdctlCmdCreator { 39 | return &nerdctlCmdCreator{ 40 | cmdCreator: cmdCreator, 41 | logger: logger, 42 | limaHomePath: limaHomePath, 43 | limactlPath: limactlPath, 44 | binPath: binPath, 45 | systemDeps: systemDeps, 46 | } 47 | } 48 | 49 | func (ncc *nerdctlCmdCreator) create(stdin io.Reader, stdout, stderr io.Writer, args ...string) Command { 50 | ncc.logger.Debugf("Creating limactl command: ARGUMENTS: %v, %s: %s", args, EnvKeyLimaHome, ncc.limaHomePath) 51 | cmd := ncc.cmdCreator.Create(ncc.limactlPath, args...) 52 | limaHomeEnv := fmt.Sprintf("%s=%s", EnvKeyLimaHome, ncc.limaHomePath) 53 | 54 | path := ncc.systemDeps.Env(EnvKeyPath) 55 | path = fmt.Sprintf(`%s%s%s`, ncc.binPath, EnvKeyPathJoiner, path) 56 | pathEnv := fmt.Sprintf("%s=%s", EnvKeyPath, path) 57 | 58 | newPathEnv := replaceOrAppend(ncc.systemDeps.Environ(), EnvKeyLimaHome, limaHomeEnv) 59 | newPathEnv = replaceOrAppend(newPathEnv, EnvKeyPath, pathEnv) 60 | 61 | cmd.SetEnv(newPathEnv) 62 | cmd.SetStdin(stdin) 63 | cmd.SetStdout(stdout) 64 | cmd.SetStderr(stderr) 65 | return cmd 66 | } 67 | -------------------------------------------------------------------------------- /e2e/vm/daemon_darwin_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin 5 | 6 | package vm 7 | 8 | import ( 9 | "context" 10 | "path/filepath" 11 | "sync" 12 | "time" 13 | 14 | "github.com/docker/docker/api/types/image" 15 | "github.com/docker/docker/client" 16 | "github.com/onsi/ginkgo/v2" 17 | "github.com/onsi/gomega" 18 | "github.com/runfinch/common-tests/option" 19 | ) 20 | 21 | var testDaemon = func(_ *option.Option, installed bool) { 22 | imageRef := "public.ecr.aws/docker/library/alpine:latest" 23 | ginkgo.Describe("Daemon smoke test", func() { 24 | ginkgo.It("docker client should be able to pull and list images", func(gCtx ginkgo.SpecContext) { 25 | // create a context which is cancelled with the ginkgo test timeout 26 | testCtx, cancelCtx := context.WithCancel(context.Background()) 27 | defer cancelCtx() 28 | go func() { 29 | defer cancelCtx() 30 | <-gCtx.Done() 31 | }() 32 | 33 | daemonSocketPath := filepath.Join(limaDataDirPath(installed), "finch", "sock", "finch.sock") 34 | apiClient, err := client.NewClientWithOpts( 35 | client.WithHost("unix://"+daemonSocketPath), 36 | client.WithVersion("v1.43"), 37 | ) 38 | gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) 39 | defer func() { 40 | gomega.Expect(apiClient.Close()).ShouldNot(gomega.HaveOccurred()) 41 | }() 42 | 43 | _, err = apiClient.ImagePull(testCtx, imageRef, image.PullOptions{}) 44 | gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) 45 | 46 | // ImagePull is asynchronous -- poll to check that the image has been pulled every second 47 | imagePulled := false 48 | wg := sync.WaitGroup{} 49 | wg.Add(1) 50 | go func(wg *sync.WaitGroup) { 51 | for { 52 | time.Sleep(1 * time.Second) 53 | images, err := apiClient.ImageList(testCtx, image.ListOptions{}) 54 | if err != nil { 55 | gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) 56 | } 57 | for _, img := range images { 58 | for _, tag := range img.RepoTags { 59 | if tag == imageRef { 60 | imagePulled = true 61 | wg.Done() 62 | return 63 | } 64 | } 65 | } 66 | } 67 | }(&wg) 68 | wg.Wait() 69 | 70 | gomega.Expect(imagePulled).Should(gomega.BeTrue()) 71 | }) 72 | }) 73 | } 74 | -------------------------------------------------------------------------------- /installer-builder/darwin/Resources/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #check running user 4 | if (( $EUID != 0 )); then 5 | echo "Please run as root." 6 | exit 7 | fi 8 | 9 | echo "Finch-__VERSION__ will be REMOVED." 10 | while true; do 11 | read -r -p "Do you wish to continue [Y/n]?" answer 12 | [[ $answer == "y" || $answer == "Y" || $answer == "" ]] && break 13 | [[ $answer == "n" || $answer == "N" ]] && exit 0 14 | echo "Please answer with 'y' or 'n'" 15 | done 16 | 17 | echo "Application uninstalling process started" 18 | sudo pkill '^socket_vmnet' 19 | sudo pkill '^qemu-system-' 20 | sudo pkill '^limactl' 21 | 22 | if [ "$$(readlink "/usr/local/bin/finch")" = "/Applications/Finch/bin/finch" ]; then sudo rm /usr/local/bin/finch; fi 23 | 24 | echo "[1/4] [DONE] Successfully deleted shortcut links" 25 | 26 | #forget from pkgutil 27 | echo "Remove historical pkgutil packages..." 28 | pkgutil --pkgs | grep '^org\.Finch\.' | while read -r pkg; do 29 | echo "Forgetting package $pkg" 30 | sudo pkgutil --forget "$pkg" > /dev/null 2>&1 31 | done 32 | 33 | if [ $? -eq 0 ] 34 | then 35 | echo "[2/4] [DONE] Successfully deleted application informations" 36 | else 37 | echo "[2/4] [ERROR] Could not delete application informations" >&2 38 | fi 39 | 40 | #remove application source distribution 41 | [ -e "/Applications/Finch" ] && rm -rf /Applications/Finch && rm -rf /opt/finch && rm -rf /private/var/run/finch-lima && rm -rf /private/etc/sudoers.d/finch-lima 42 | if [ $? -eq 0 ] 43 | then 44 | echo "[3/4] [DONE] Successfully deleted application" 45 | else 46 | echo "[3/4] [ERROR] Could not delete application" >&2 47 | fi 48 | 49 | #clean up ~/.finch directory 50 | while true; do 51 | read -r -p "Delete ~/.finch containing persistent user data [Y/n]? " answer 52 | if [[ $answer == "y" || $answer == "Y" ]] 53 | then 54 | [ -d ~/.finch ] && rm -rf ~/.finch 55 | if [ $? -eq 0 ] 56 | then 57 | echo "[4/4] [DONE] Successfully deleted ~/.finch" 58 | else 59 | echo "[4/4] [ERROR] Could not delete ~/.finch" >&2 60 | fi 61 | break 62 | elif [[ $answer == "n" || $answer == "N" || $answer == "" ]] 63 | then 64 | echo "[4/4] Deletion of ~/.finch was aborted." 65 | break 66 | else 67 | echo "Please answer with 'y' or 'n'" 68 | fi 69 | done 70 | 71 | echo "Application uninstall process finished" 72 | exit 0 73 | -------------------------------------------------------------------------------- /docs/cmd/finch_pull.md: -------------------------------------------------------------------------------- 1 | # finch pull 2 | 3 | Pull an image from a registry. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS. 4 | 5 | ```text 6 | finch pull [flags] NAME[:TAG] 7 | ``` 8 | 9 | ## Options 10 | 11 | ```text 12 | --all-platforms Pull content for all platforms 13 | --cosign-certificate-identity string The identity expected in a valid Fulcio certificate for --verify=cosign. Valid values include email address, DNS names, IP addresses, and URIs. Either --cosign-certificate-identity or --cosign-certificate-identity-regexp must be set for keyless flows 14 | --cosign-certificate-identity-regexp string A regular expression alternative to --cosign-certificate-identity for --verify=cosign. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --cosign-certificate-identity or --cosign-certificate-identity-regexp must be set for keyless flows 15 | --cosign-certificate-oidc-issuer string The OIDC issuer expected in a valid Fulcio certificate for --verify=cosign,, e.g. https://token.actions.githubusercontent.com or https://oauth2.sigstore.dev/auth. Either --cosign-certificate-oidc-issuer or --cosign-certificate-oidc-issuer-regexp must be set for keyless flows 16 | --cosign-certificate-oidc-issuer-regexp string A regular expression alternative to --certificate-oidc-issuer for --verify=cosign,. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --cosign-certificate-oidc-issuer or --cosign-certificate-oidc-issuer-regexp must be set for keyless flows 17 | --cosign-key string Path to the public key file, KMS, URI or Kubernetes Secret for --verify=cosign 18 | -h, --help help for pull 19 | --ipfs-address string multiaddr of IPFS API (default uses $IPFS_PATH env variable if defined or local directory ~/.ipfs) 20 | --platform strings Pull content for a specific platform 21 | -q, --quiet Suppress verbose output 22 | --unpack string Unpack the image for the current single platform (auto/true/false) (default "auto") 23 | --verify string Verify the image (none|cosign|notation) (default "none") 24 | ``` 25 | -------------------------------------------------------------------------------- /scripts/canary-deb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -o pipefail 4 | 5 | ARCH=$(dpkg --print-architecture) 6 | echo "Detected architecture: ${ARCH}" 7 | 8 | if [[ -z "${GITHUB_WORKSPACE}" ]]; then 9 | GITHUB_WORKSPACE=${PWD} 10 | fi 11 | 12 | # 13 | # GitHub artifact downloading 14 | # 15 | 16 | github_artifact_dir=${GITHUB_WORKSPACE}/github-release 17 | 18 | req=$(curl https://api.github.com/repos/runfinch/finch/releases/latest) 19 | deb_asset=$(echo ${req} | jq --arg suffix "${ARCH}.deb" '.assets[] | select(.name|endswith($suffix))') 20 | 21 | deb_url=$(echo ${deb_asset} | jq -r '.url') 22 | filename=$(echo ${deb_asset} | jq -r '.name') 23 | 24 | sha_unparsed=$(echo ${deb_asset} | jq -r '.digest') 25 | while IFS=':' read -ra sha_arr; do 26 | expected_shasum=${sha_arr[1]} 27 | done <<< "${sha_unparsed}" 28 | 29 | mkdir ${github_artifact_dir} 30 | curl -L -H "Accept: application/octet-stream" -o ${github_artifact_dir}/${filename} ${deb_url} 31 | 32 | github_file_shasum=$(sha256sum ${github_artifact_dir}/${filename} | awk '{print $1}') 33 | 34 | if [[ $(diff <(echo ${expected_shasum}) <(echo ${github_file_shasum})) ]]; then 35 | printf "shasum mismatch from GitHub\nexpected:%1\ngot:%s\n" expected_shasum github_file_shasum 36 | exit 1 37 | fi 38 | 39 | # 40 | # APT repo downloading 41 | # 42 | 43 | curl -fsSL https://artifact.runfinch.com/deb/GPG_KEY.pub | gpg --dearmor -o /usr/share/keyrings/runfinch-finch-archive-keyring.gpg 44 | echo "deb [signed-by=/usr/share/keyrings/runfinch-finch-archive-keyring.gpg arch=${ARCH}] https://artifact.runfinch.com/deb noble main" | sudo tee /etc/apt/sources.list.d/runfinch-finch.list 45 | 46 | # This should only update the runfinch repo. 47 | # If this breaks, changing it to `sudo apt-get update` should be acceptable, it just takes longer to run. 48 | sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/runfinch-finch.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" 49 | 50 | apt-get download runfinch-finch 51 | apt_file=${GITHUB_WORKSPACE}/${filename} 52 | apt_file_shasum=$(sha256sum ${apt_file} | awk '{print $1}') 53 | 54 | # 55 | # Compare shasums 56 | # 57 | 58 | if [[ $(diff <(echo ${apt_file_shasum}) <(echo ${expected_shasum})) ]]; then 59 | echo "❌ sha256sum mismatch!" 60 | echo "apt repo shasum: ${apt_file_shasum}" 61 | echo "GitHub release shasum: ${github_file_shasum}" 62 | exit 1 63 | else 64 | echo "✅ shasum ${apt_file_shasum} identical" 65 | fi 66 | -------------------------------------------------------------------------------- /pkg/flog/logrus.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | package flog 5 | 6 | import ( 7 | "github.com/sirupsen/logrus" 8 | ) 9 | 10 | // Logrus implements the Logger interface. 11 | type Logrus struct{} 12 | 13 | var _ Logger = (*Logrus)(nil) 14 | 15 | // NewLogrus returns a new logrus logger. 16 | func NewLogrus() *Logrus { 17 | return &Logrus{} 18 | } 19 | 20 | // Debugf logs a message at level Debug. 21 | func (l *Logrus) Debugf(format string, args ...interface{}) { 22 | logrus.Debugf(format, args...) 23 | } 24 | 25 | // Debugln logs a message at level Debug. 26 | func (l *Logrus) Debugln(args ...interface{}) { 27 | logrus.Debugln(args...) 28 | } 29 | 30 | // Info logs a message at level Info. 31 | func (l *Logrus) Info(args ...interface{}) { 32 | logrus.Info(args...) 33 | } 34 | 35 | // Infof logs a message at level Info. 36 | func (l *Logrus) Infof(format string, args ...interface{}) { 37 | logrus.Infof(format, args...) 38 | } 39 | 40 | // Infoln logs a message at level Info. 41 | func (l *Logrus) Infoln(args ...interface{}) { 42 | logrus.Infoln(args...) 43 | } 44 | 45 | // Warnln logs a message at level Warn. 46 | func (l *Logrus) Warnln(args ...interface{}) { 47 | logrus.Warnln(args...) 48 | } 49 | 50 | // Warnf logs a message at level Warn. 51 | func (l *Logrus) Warnf(format string, args ...interface{}) { 52 | logrus.Warnf(format, args...) 53 | } 54 | 55 | // Error logs a message at level Error. 56 | func (l *Logrus) Error(args ...interface{}) { 57 | logrus.Error(args...) 58 | } 59 | 60 | // Errorf logs a message at level Error. 61 | func (l *Logrus) Errorf(format string, args ...interface{}) { 62 | logrus.Errorf(format, args...) 63 | } 64 | 65 | // Fatal logs a message at level Fatal. 66 | func (l *Logrus) Fatal(args ...interface{}) { 67 | logrus.Fatal(args...) 68 | } 69 | 70 | // SetLevel sets the level of the logger. 71 | func (l *Logrus) SetLevel(level Level) { 72 | switch level { 73 | case Debug: 74 | logrus.SetLevel(logrus.DebugLevel) 75 | case Panic: 76 | logrus.SetLevel(logrus.PanicLevel) 77 | } 78 | } 79 | 80 | // SetFormatter sets the formatter of the logger. 81 | func (l *Logrus) SetFormatter(formatter Formatter) { 82 | switch formatter { 83 | case Text: 84 | logrus.SetFormatter(&logrus.TextFormatter{}) 85 | case TextWithoutTruncation: 86 | logrus.SetFormatter(&logrus.TextFormatter{ 87 | DisableLevelTruncation: true, 88 | }) 89 | case JSON: 90 | logrus.SetFormatter(&logrus.JSONFormatter{}) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /.github/workflows/upload-msi-to-release.yaml: -------------------------------------------------------------------------------- 1 | name: Upload installer 2 | on: 3 | workflow_dispatch: # Trigger this workflow from tag 4 | workflow_call: 5 | inputs: 6 | ref_name: 7 | required: true 8 | type: string 9 | 10 | permissions: 11 | id-token: write # This is required for requesting the JWT 12 | contents: write # This is required for uploading the release assets 13 | jobs: 14 | get-version-tag: 15 | name: Get the version, tag and validate the format 16 | runs-on: ubuntu-latest 17 | timeout-minutes: 2 18 | outputs: 19 | tag: ${{ steps.check-tag.outputs.tag }} 20 | version: ${{ steps.check-tag.outputs.version }} 21 | steps: 22 | - name: Check tag from workflow input and github ref 23 | id: check-tag 24 | run: | 25 | if [ -n "${{ inputs.ref_name }}" ]; then 26 | tag=${{ inputs.ref_name }} 27 | else 28 | tag=${{ github.ref_name }} 29 | fi 30 | echo "tag=$tag" >> ${GITHUB_OUTPUT} 31 | 32 | version=${tag#v} 33 | if [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then 34 | echo "Version matches format: $version" 35 | else 36 | echo "Error: Version $version doesn't match format." 37 | exit 1 38 | fi 39 | echo "version=$version" >> ${GITHUB_OUTPUT} 40 | 41 | upload-windows-msi: 42 | needs: get-version-tag 43 | runs-on: ubuntu-latest 44 | timeout-minutes: 2 45 | steps: 46 | - name: configure aws credentials 47 | uses: aws-actions/configure-aws-credentials@00943011d9042930efac3dcd3a170e4273319bc8 # v5.1.0 48 | with: 49 | role-to-assume: ${{ secrets.ROLE }} 50 | role-session-name: download-installer-session 51 | aws-region: ${{ secrets.REGION }} 52 | - name: Download installers and dependency source code 53 | run: | 54 | aws s3 cp s3://${{ secrets.INSTALLER_PRIVATE_BUCKET_NAME }}/Finch-${{ needs.get-version-tag.outputs.tag }}.msi Finch-${{ needs.get-version-tag.outputs.tag }}.msi 55 | - name: Upload installers and dependency source code to release 56 | uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v0.1.15 57 | with: 58 | tag_name: ${{ needs.get-version-tag.outputs.tag }} 59 | files: | 60 | Finch-${{ needs.get-version-tag.outputs.tag }}.msi 61 | - name: Delete installers and dependency source code 62 | run: rm -rf Finch-${{ needs.get-version-tag.outputs.tag }}.msi -------------------------------------------------------------------------------- /e2e/vm/version_remote_test.go: -------------------------------------------------------------------------------- 1 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | //go:build darwin || windows 5 | 6 | package vm 7 | 8 | import ( 9 | "bytes" 10 | "strings" 11 | "text/template" 12 | 13 | "github.com/onsi/ginkgo/v2" 14 | "github.com/onsi/gomega" 15 | "github.com/runfinch/common-tests/command" 16 | "github.com/runfinch/common-tests/option" 17 | 18 | "github.com/runfinch/finch/pkg/version" 19 | ) 20 | 21 | const ( 22 | nerdctlVersion = "v2.1.3" 23 | buildKitVersion = "v0.23.2" 24 | containerdVersion = "v2.1.3" 25 | runcVersion = "1.3.3" 26 | ) 27 | 28 | type Versions struct { 29 | FinchVersion string 30 | FinchCommit string 31 | NerdctlVersion string 32 | BuildKitVersion string 33 | ContainerdVersion string 34 | RuncVersion string 35 | } 36 | 37 | var versions = Versions{ 38 | FinchVersion: strings.ReplaceAll(version.Version, ".", "\\."), 39 | FinchCommit: strings.ReplaceAll(version.GitCommit, ".", "\\."), 40 | NerdctlVersion: strings.ReplaceAll(nerdctlVersion, ".", "\\."), 41 | BuildKitVersion: strings.ReplaceAll(buildKitVersion, ".", "\\."), 42 | ContainerdVersion: strings.ReplaceAll(containerdVersion, ".", "\\."), 43 | RuncVersion: strings.ReplaceAll(runcVersion, ".", "\\."), 44 | } 45 | 46 | // Checks finch version. 47 | var testVersion = func(o *option.Option) { 48 | ginkgo.Describe("Check finch version", func() { 49 | ginkgo.It("Should print finch version information", func() { 50 | tmpl, err := template.New("versionTemplate").Parse(`Client: 51 | Version: {{ .FinchVersion }} 52 | GitCommit: {{ .FinchCommit }} 53 | OS\/Arch: [A-Za-z0-9]+\/[A-Za-z0-9]+ 54 | nerdctl: 55 | Version: {{ .NerdctlVersion }} 56 | GitCommit: [a-z0-9]{40} 57 | buildctl: 58 | Version: {{ .BuildKitVersion }} 59 | GitCommit: [a-z0-9]{40} 60 | 61 | Server: 62 | containerd: 63 | Version: {{ .ContainerdVersion }} 64 | GitCommit: [a-z0-9]{40} 65 | runc: 66 | Version: {{ .RuncVersion }} 67 | GitCommit: v[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+-g[a-z0-9]{7,8})? 68 | `) 69 | gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) 70 | var versionMatcher bytes.Buffer 71 | err = tmpl.Execute(&versionMatcher, versions) 72 | gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) 73 | // command.StdoutStr is not used because it trims both leading and trailing spaces, 74 | // while we want an exact match here. 75 | gomega.Expect(string(command.Stdout(o, "version"))).Should(gomega.MatchRegexp(versionMatcher.String())) 76 | }) 77 | }) 78 | } 79 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", 3 | "release-type": "go", 4 | "changelog-sections": [ 5 | { 6 | "type": "build", 7 | "section": "Build System or External Dependencies", 8 | "hidden": false 9 | }, 10 | { 11 | "type": "exp", 12 | "section": "Experimental", 13 | "hidden": false 14 | }, 15 | { 16 | "type": "feat", 17 | "section": "Features", 18 | "hidden": false 19 | }, 20 | { 21 | "type": "fix", 22 | "section": "Bug Fixes", 23 | "hidden": false 24 | }, 25 | { 26 | "type": "revert", 27 | "section": "Reverts", 28 | "hidden": false 29 | }, 30 | { 31 | "type": "chore", 32 | "section": "Miscellaneous Chores", 33 | "hidden": true 34 | }, 35 | { 36 | "type": "docs", 37 | "section": "Documentation", 38 | "hidden": true 39 | }, 40 | { 41 | "type": "refactor", 42 | "section": "Code Refactoring", 43 | "hidden": true 44 | }, 45 | { 46 | "type": "test", 47 | "section": "Tests", 48 | "hidden": true 49 | }, 50 | { 51 | "type": "ci", 52 | "section": "Continuous Integration", 53 | "hidden": true 54 | } 55 | ], 56 | "packages": { 57 | ".": {} 58 | }, 59 | "pull-request-header": "Ready for new finch release - Please verify the checklist items in the bottom of this PR before merging", 60 | "pull-request-footer": "---\n\n### 🤖 IMPORTANT Please Read\n\nThis PR was generated automatically by [release-please](https://github.com/googleapis/release-please).\n\n**Please verify the following before merging this PR:**\n1. The Sync Submodules workflow has completed successfully in [finch-core](https://github.com/runfinch/finch-core/actions/workflows/submodulesync.yaml) repo\n2. The [Sync Submodules and Dependencies](https://github.com/runfinch/finch/actions/workflows/sync-submodules-and-deps.yaml) Workflow has completed successfully in this repo and the subsequent PR has been merged\n3. Latest run of [samcli-vm](https://github.com/runfinch/finch-daemon/actions/workflows/samcli-vm.yaml) tests are sucessful\n\n**Need to make changes?** Push additional commits to main and this PR will be updated automatically." 61 | } 62 | --------------------------------------------------------------------------------