Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 116 additions & 55 deletions .dagger/main.go

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: CI

# Builds and tests Cairn entirely from public sources. The Dagger `ci` function
# fetches the TamaGo fork, the shared Kyanite modules and the tamago-go compiler
# release from public GitHub, cross-compiles the AST2700 payload and runs the
# host unit tests — so this workflow needs no secrets and no extra inputs.

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🛡️ Detected with Advanced Tier | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,80p' .github/workflows/ci.yml
sed -n '1,80p' dagger.json
rg -n 'Host\(|CurrentModule|ModuleSource|Directory\(|Secret|GITHUB_TOKEN|git/config|persist-credentials' .dagger .github

Repository: kyanitecomputer/cairn

Length of output: 2031


🌐 Web query:

Dagger GitHub Action pull request module source .git directory checkout persisted credentials accessibility

💡 Result:

Inspection citation: inspection_997438e8922fe1ee007d7cf214560cca

<source_evidence>

<title>actions/checkout</title> https://github.com/actions/checkout - Safer fork pull request handling: checkout now refuses to check out fork pull request code by default when the workflow is triggered by `pull_request_target` or `workflow_run`. These triggers run with the base repository&`#39`;s `GITHUB_TOKEN`, secrets, and runner access, where executing a fork&`#39`;s code commonly leads to "pwn request" vulnerabilities. - To opt in after reviewing the risks, set the new `allow-unsafe-pr-checkout: true` input. ... - Improved credential security: `persist-credentials` now stores credentials in a separate file under `$RUNNER_TEMP` instead of directly in `.git/config` - No workflow changes required — `git fetch`, `git push`, etc. continue to work automatically - Running authenticated git commands from a Docker container action requires Actions Runner v2.329.0 or later ... This action checks-out your repository under `$GITHUB_WORKSPACE`, so your workflow can access it. ... The auth token is persisted in the local git config. This enables your scripts to run authenticated git commands. The token is removed during post-job cleanup. Set `persist-credentials: false` to opt-out. ... # Usage ```yaml - uses: actions/checkout@v7 with: # Repository name with owner. For example, actions/checkout # Default: ${{ github.repository }} repository: &`#39`;&`#39`; ... # Personal access token (PAT) used to fetch the repository. The PAT is configured # with the local git config, which enables your scripts to run authenticated git # commands. The post-job step removes the PAT. # # We recommend using a service account with the least permissions necessary. Also # when generating a new PAT, select the least scopes necessary. # # Learn more about creating and using encrypted secrets # # Default: ${{ github.token }} token: &`#39`;&`#39`; ... # SSH key used to fetch the repository. The SSH key is configured with the local ... git config, ... enables your scripts to run authenticated git commands. The ... # post-job step removes the ... account with the ... # Whether to configure the token or SSH key with the local git config # Default: true persist-credentials: &`#39`;&`#39`; ... # Relative path under $GITHUB_WORKSPACE to place the repository path: &`#39`;&`#39`; ... # Whether to checkout submodules: `true` to checkout submodules or `recursive` to # recursively checkout submodules. # # When the `ssh-key` input is not provided, SSH URLs beginning with # `git@github.com:` are converted to HTTPS. # # Default: false submodules: &`#39`;&`#39`; ... # Add repository path as safe.directory for Git global config by running `git # config --global --add safe.directory <path>` # Default: true set-safe-directory: &`#39`;&`#39`; ... # Required to check out fork pull request code from a workflow triggered by # `pull_request_target` or `workflow_run`. These workflows run with the base # repository&`#39`;s GITHUB_TOKEN, secrets, default-branch cache scope, and runner # access; fetching and executing a fork&`#39`;s code in that trusted context commonly # leads to "pwn request" vulnerabilities. Set to `true` only after reviewing the # risks at https://gh.io/securely-using-pull_request_target. # Default: false allow-unsafe-pr-checkout: &`#39`;&`#39`; ... - Scenarios - Fetch only the root files - Fetch only the root files and `.github` and `src` folder - Fetch only a single file - Fetch all history for all tags and branches - Checkout a different branch - Checkout HEAD^ - Checkout multiple repos (side by side) - Checkout multiple repos (nested) - Checkout multiple repos (private) - Checkout pull request HEAD commit instead of merge commit - Checkout pull request on closed event - Push a commit using the built-in token - Push a commit to a PR using the built-in token ... ## Fetch only the root files and `.github` and `src` folder ... ```yaml - uses: actions/checkout@v7 with: sparse-checkout: | .github src ... ## Checkout pull request HEAD commit instead of merge commit ... ```yaml - uses: actions/checkout@v7 with: ref: ${{ github.event.pul…[truncated] <title>TIL: actions/checkout can leak GitHub credentials</title> https://yossarian.net/til/post/actions-checkout-can-leak-github-credentials/ TIL: actions/checkout can leak GitHub credentials # actions/checkout can leak GitHub credentials 2024-08-17 `actions/checkout` is one of GitHub Actions&`#39`; official, blessed actions: it&`#39`;s used by millions of CI workflows to perform `git` repository checkouts. `actions/checkout` also contains a significant security footgun: by default, it&`#39`;ll persist a copy of the workflow&`#39`;s credential (either the default `secrets.GITHUB_TOKEN` one or a custom-supplied one) in the checked-out repository&`#39`;s `.git/config`. This wouldn&`#39`;t be too bad, except that it&`#39`;s somewhat common for CI workflows to then archive and upload the repository as a workflow artifact for use in subsequent steps. A team at Palo Alto Networks found dozens of projects that inadvertently leak their credentials through this and similar artifact vectors. GitHub knows about this and considers it intentional behavior, which seems not great™ to me. If you don&`#39`;t want credentials added to your `.git/config`, they suggest running steps like `actions/checkout` like so: ```yaml uses: actions/checkout@v4 with: persist-credentials: false ``` TL;DR: By default, `actions/checkout` will silently introduce secrets into your repository, even if you maintain proper `git` hygiene and never check any secrets in. The only way to avoid this is to pass `persist-credentials: false` whenever using `actions/checkout`. <title>ci(security): scan secrets via gitleaks CLI in Dagger, not gitleaks-action</title> GitHub pull request 632 in enix/x509-certificate-exporter (link omitted to avoid creating a cross-reference) * **Chores** * Updated secret scanning to run through the existing Dagger pipeline for working-tree scanning. * Hardened CI checkouts by disabling persisted Git credentials and adjusted scan checkout depth. * Updated pinned scanning image versions and refreshed `.gitleaksignore` rules. ... > > > > > > --- > > > > 📝 Walkthrough > > ## Walkthrough > > Adds a `Gitleaks` method to the Dagger module (`dagger/security.go`) that mounts a directory into a pinned gitleaks container and runs a secret scan with exit-code enforcement. Pins the container image in `dagger/base.go`, wires a `security:gitleaks` task into `Taskfile.yml`, migrates the GitHub Actions workflow job from `gitleaks/gitleaks-action` to `dagger/dagger-for-github`, adds gitleaks:allow suppressions to code containing passphrases, and updates `CLAUDE.md` accordingly. > > ## Changes ... > | **Gitleaks image pin and Dagger method** `dagger/base.go`, `dagger/security.go` | Adds `gitleaksImage` digest constant and `X509Ce.Gitleaks(ctx, source)` method that mounts the source directory at `/scan` and runs `gitleaks dir` with `--no-banner`, `--redact`, `--verbose`, and `--exit-code 1`. | ... > | **Taskfile task and integration** `Taskfile.yml` | Adds `security:gitleaks` task invoking `dagger call gitleaks` and includes it in the top-level `security` task before other security checks. | ... > | **CI workflow migration** `.github/workflows/security.yaml` | Replaces the `gitleaks/gitleaks-action`-based secret-leaks job with a `dagger/dagger-for-github` call, removes PR-comment permissions and license/token environment variables, and sets `persist-credentials: false` across multiple security jobs to prevent GitHub token persistence in the checked-out workspace. | ... go` module documentation ... and ignore-scope behavior. ... `56-56`: **Consider disabling persisted Git credentials in the secrets job checkout.** At line 56, `actions/checkout` retains credentials in git config. Since this job executes Dagger code on pull requests, setting `persist-credentials: false` reduces unnecessary token exposure in the workspace. Suggested patch ```diff secrets: name: Secret leaks (Gitleaks) runs-on: ubuntu-latest steps: - uses: actions/checkout@df4cb1c # v6 + with: + persist-credentials: false - uses: dagger/dagger-for-github@27b130b # v8 ``` ... 🤖 Prompt for AI Agents ... In @.github/workflows/security.yaml at line 56, The actions/checkout step at the specified location is retaining Git credentials in the workspace by default. Add the `persist-credentials: false` parameter to the checkout action to disable credential persistence, which reduces unnecessary token exposure when executing Dagger code on pull requests. This parameter should be added as a new line within the checkout step configuration. ... all review comments ... - Line 56: The ... checkout step at ... is retaining Git ... credentials in the workspace by default. Add the `persist-credentials: false` ... parameter to the checkout action to disable credential persistence, which reduces unnecessary token exposure when executing Dagger code on pull requests. ... This parameter should be added as a new line within the checkout step configuration. ... **Add `persist-credentials: false` for security hardening.** The checkout step should explicitly disable credential persistence to prevent the GitHub token from being exposed to subsequent steps. This is especially important in security workflows that invoke third-party tools or containers. 🔒 Proposed fix ```diff - uses: actions/checkout@df4cb1c # v6 + with: + persist-credentials: false ``` 🤖 Prompt for AI Agents ``` ... In @.github/workflows/security.yaml at line 56, The actions/checkout step in the security workflow at line 56 lacks the persist-credentials: false configuration option. Add persist-credentials: false as …[truncated] <title>Remove `persist-credentials` or change the default to `false` · Issue `#485` · actions/checkout · GitHub</title> GitHub issue 485 in actions/checkout (link omitted to avoid creating a cross-reference) Remove `persist-credentials` or change the default to `false` · Issue `#485` · actions/checkout · GitHub # Remove persist-credentials or change the default to false `#485` New issue New issue Open opened on Apr 26, 2021 Currently one has to resort to explicitly specifying`persist-credentials: false` to avoid the credentials being persistent. My understanding is that persisting the credentials gives every step in the job that occurs after`actions/checkout@v2` implicit access to the token. This is not what people expect and this leads people to write jobs that expose their repo to more risk than they otherwise would. I propose the`persist-credentials` feature be removed completely and then v3 be released. Otherwise, if that&`#39`;s not practical, then at least the default should be changed to`false`. <title>fix: use git credential helper&`#39`;s username for modules with http auth · Pull Request `#10427` · dagger/dagger</title> GitHub pull request 10427 in dagger/dagger (link omitted to avoid creating a cross-reference) ## fix: use git credential helper&`#39`;s username for modules with http auth ... In `#8989`, an issue emerged with GitLab CI&`#39`;s `CI_JOB_TOKEN`s: Right now, when accessing remote modules via HTTP authentication using `dagger call -m gitlab.com/...`, the username is hardcoded to `x-access-token` (except for bitbucket.com). However, as specified in [GitLab’s documentation](https://docs.gitlab.com/ci/jobs/ci_job_token/#use-a-job-token), username `gitlab-ci-token` is required when using basic authentication with `CI_JOB_TOKEN`. In the discussion, we recognized that not only receiving the secret but also the username from the git credential helper would solve the issue best. ... - Add another option `httpAuthUsername` to `RemoteGitRepository` and pass the username alongside `httpAuthToken`. It would also change the interface of [`GitRepository`](https://docs.dagger.io/api/reference/#definition-GitRepository), and while this isn&`#39`;t related to the original problem, it makes it easier to set the username when calling a git repo from within a module (currently, the [`httpAuthHeader`](https://docs.dagger.io/api/reference/#query-git) arg must be composed manually). This was my first approach until I realized I could solve the issue without extensive code refactoring. However, I was considering adding two helper functions to [`GitRepository`](https://docs.dagger.io/api/reference/#definition-GitRepository): `.WithHttpAuthHeaderFromBasicAuth(username, password)` and `.WithHttpAuthHeaderFromBearerAuth(token)` to simplify [`httpAuthHeader`](https://docs.dagger.io/api/reference/#query-git) formatting. ... - Use `httpAuthHeader` instead of `httpAuthToken` to leverage existing code with minimal refactoring. While this solution works for the PR, it reveals overlapping logic between `core.RemoteGitRepository.setup` and `core.schema.gitSchema.git`. Further refactoring may be beneficial to address this duplication. ... Currently, this PR doesn&`#39`;t address another desirable CLI feature: being able to pass credentials within the URL. At present, username and password parameters in URLs are ignored to best of my knowledge. Adding this capability would allow using the format `dagger call -m https://gitlab-ci-token:${CI_JOB_TOKEN}`@gitlab.com/`...` and also passing repositories as directories from the command line in general. This would eliminate the need to set up a git credential helper, which can be cumbersome in some CI environments. However, during implementation, I discovered that additional refactoring is needed to make this work. Therefore, this PR only addresses the GitLab CI issue from `#8989`. ... > LGTM, we need a test though. > > `@grouville` why do we need to make changes to the test repo here? This should just be possible to test just using `ExperimentalServiceHost`. > > There&`#39`;s no tests that cover the behavior of the auto-loading credentials for just plain git clones (only for modules). https://github.com/dagger/dagger/blob/84dc5b3ba37238d957db1025c70dca797d35a055/core/integration/module_test.go#L5774-L5800 > > We should adapt the above to `git_test.go` and add tests for this through there. ... > Hey `@jedevc`, I’m not 100% sure I’ve fully grasped all your points here 🙏👼 > > Just to confirm my understanding clearly: > > 1. On the testing approach, you asked: > > > `@grouville` why do we need to make changes to the test repo here? This should just be possible to test just using ExperimentalServiceHost. > > My initial intent was testing the specific GitLab edge case (CI_JOB_TOKEN requires explicit username). But your suggestion seems broader: instead of an integration test using a real token, you’d prefer spinning up a local git server with ExperimentalServiceHost and checking credentials locally. Did I get that right? > > 1. About “plain git clones”, you wrote: > > > `There&`#39`;s no tests that cover the behavior of the auto-loading credentials for just plain git …[truncated]

Citations:

  • 1: https://github.com/actions/checkout
  • 2: https://yossarian.net/til/post/actions-checkout-can-leak-github-credentials/
  • 3: GitHub pull request 632 in enix/x509-certificate-exporter (link omitted to avoid creating a cross-reference)
  • 4: GitHub issue 485 in actions/checkout (link omitted to avoid creating a cross-reference)
  • 5: GitHub pull request 10427 in dagger/dagger (link omitted to avoid creating a cross-reference)
  • 6: GitHub pull request 6992 in dagger/dagger (link omitted to avoid creating a cross-reference)
  • 7: GitHub pull request 9131 in dagger/dagger (link omitted to avoid creating a cross-reference)
  • 8: GitHub issue 8989 in dagger/dagger (link omitted to avoid creating a cross-reference)
  • 9: GitHub pull request 6575 in dagger/dagger (link omitted to avoid creating a cross-reference)

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- .dagger outline ---'
ast-grep outline .dagger/main.go --view expanded
printf '%s\n' '--- host/filesystem/process-related symbols ---'
rg -n -C 3 'Host\(|Client\(|Directory\(|WithDirectory|WithMounted|WithExec|Exec\(|Open|Read|File\(|NewFile|dagger\.|os\.(ReadFile|Open|Getwd|Stat|ReadDir)|filepath|exec\.Command|GITHUB_TOKEN|git/config|\.git' .dagger/main.go
printf '%s\n' '--- module source and CI references ---'
cat -n dagger.json
cat -n .github/workflows/ci.yml

Repository: kyanitecomputer/cairn

Length of output: 12801


🌐 Web query:

Dagger Go SDK module sandbox Host Directory access from a module and dagger call GitHub Actions workspace

💡 Result:

Inspection citation: inspection_b5cfbf450be3939450522f7ad3fe2fdf

<source_evidence>

<title>Add `Workspace` API and caching support (`#11874`) · b5ea047 · dagger/dagger</title> https://github.com/dagger/dagger/commit/b5ea047d5e543c7d8524e28cfd2342944e147bcc - api: add Workspace.directory and Workspace.file ... Add directory() and file() methods to the Workspace type, providing host-backed filesystem access scoped to the workspace root. ... - directory(path, include, exclude) returns a Directory snapshot from the host, with the path resolved relative to the workspace root. Delegates to Host.Directory for the actual host filesystem sync. ... - file(path) returns a single File from the host, resolved relative to the workspace root. Uses the same host directory + file extraction pattern as Host.file. ... - fix: route Workspace.directory/file through the workspace owner&`#39`;s client session ... When a module function receives an injected Workspace and calls workspace.directory() or workspace.file(), the host filesystem operation needs to go through the original client&`#39`;s session — not the module&`#39`;s session (which doesn&`#39`;t have host access). ... The fix: ... - Store the creating client&`#39`;s ID in the Workspace object when it&`#39`;s constructed by currentWorkspace - In the directory/file resolvers, override the client metadata in context to the workspace&`#39`;s owning client ID before routing through the host.directory dagql pipeline - This ensures the filesync request reaches the correct session that has access to the host filesystem ... - Basic workspace arg: module reads a file from host via Workspace - Directory entries: module lists workspace directory contents - Include/exclude patterns on Workspace.directory - Cache invalidation: host filesystem changes reflected without cache buster - Workspace.file: reading file content from host - Subdirectory access via Workspace.directory - Workspace args are magical (not exposed as CLI flags, but function is callable) ... All tests use the Dang SDK and the &`#39`;dagger module init&`#39`; command to scaffold workspace modules. ... - add + use pathutil.SandboxedRelativePath ... The workspace schema had a local resolveWorkspacePath function that resolved user-provided paths relative to a root directory while preventing directory traversal escapes. This had two problems: ... 1. It used filepath (OS-dependent) instead of path (POSIX), which ... would break on Windows clients. The engine always runs on Linux, but workspace roots from Windows clients arrive as forward-slash paths with drive prefixes (e.g. &`#39`;C:/Users/foo&`#39`;) since the client normalizes backslashes before sending. Linux&`#39`;s filepath.IsAbs doesn&`#39`;t recognize &`#39`;C:/...&`#39`; as absolute, and filepath.Clean won&`#39`;t handle drive letters correctly. ... Moved the logic to pathutil.SandboxedRelativePath which: ... - Normalizes backslashes to forward slashes for Windows client paths - Strips drive letters (via pathutil.GetDrive) or leading &`#39`;/&`#39`; so absolute user paths are treated as relative to the root ... - Uses normalizePath (already in pathutil) for consistent handling - Verifies the resolved path doesn&`#39`;t escape root via &`#39`;..&`#39`; ... Also switched workspace.go from filepath to path (POSIX) throughout, since all path operations run on the Linux engine against forward-slash-normalized paths. ... Added 12 unit tests ... relative paths, dot, absolute paths, ... dotdot escape attempts, Windows backslashes, drive letters, and Windows roots with drive prefixes. ... +// TestWorkspaceBlueprint verifies that a blueprint module accepting a Workspace +// argument can access the host filesystem, just like a toolchain module. +func (WorkspaceSuite) TestBlueprint(ctx context.Context, t *testctx.T) { + c := connect(ctx, t) + + ctr := workspaceBase(t, c). + WithNewFile("hello.txt", "hello from workspace"). ... + With(initDangBlueprint("greeter", ` ... +// TestWorkspaceArg verifies that a module function accepting a Workspace +// argument can access the host filesystem. +func (WorkspaceSuite) TestWorkspaceArg(ctx context.Context, t *testctx.T) { + c := connect(ctx, t) + + ctr := workspaceBase(t, c). + WithNewFile("hello.txt…[truncated] <title>Remove Host API from module SDK codegen. · Pull Request `#6535` · dagger/dagger</title> GitHub pull request 6535 in dagger/dagger (link omitted to avoid creating a cross-reference) ## Remove Host API from module SDK codegen. ... ## Modules that use the Host API to read source files ... Previously, module containers set their working directory to the directory containing the module&`#39`;s source code. You could then read files from that directory with calls like `dag.Host().File("./some/file.txt")`. ... Now, module containers are set to an initially empty scratch directory, so those calls will not work anymore. ... To use files/directories from the module source code, you can instead: ... 1. Directories - `dag.CurrentModule().Source().Directory("some/subdir")` 2. Files - `dag.CurrentModule().Source().File("some/file.txt")` ... Additionally, it used to technically be possible to use files/directories from anywhere in the root dir loaded for a module in the case where `"root"` was configured in `dagger.json`. This is no longer possible; instead anything you need to use from outside the module&`#39`;s source code directory should be accepted as an argument to a function or the module constructor. ... One final use case to mention: if you need to create new files/directories and then load them into the dagger API during module execution, this is still possible. ... 1. Directories - `dag.CurrentModule().Workdir("./some/dir")` 2. Files - `dag.CurrentModule().WorkdirFile("./some/file.txt")` ... The new dag.CurrentModule() API replaces the need for the Host API and gives more controlled functionality that is specific to modules. ... > I only ran a subset of tests locally, but didn&`#39`;t run `TestModuleDaggerCallArgTypes/service_args` which I now see is failing due to the fact that you pass a service created w/ the host API from the CLI to a module, which no longer knows anything about host and thus can&`#39`;t load its ID... > > Been thinking through whether there&`#39`;s any reasonable options here that also maintains the current approach, but don&`#39`;t see any; only see options that would hack dagql in unreasonable ways. > > I am going to give a shot at a different approach that still allows the host schema to be loaded for module clients on the graphql level, but just not presented to SDKs for codegen. Should create same end effect while still allowing use cases like this to work. ... The new approach described in previous comment works much ... and thankfully isn ... t quite as kludgy as I originally ... : https://github.com/dagger/dagger/pull/6535/commits/685e6e52862ad2bb0a296a0546a02656e3538618 > > I could actually see it being useful in general outside this use case; e.g. I considered doing the same thing to block the `Query.blob` API from *all* SDK clients since that&`#39`;s very much internal only (backed out because I really don&`#39`;t want to expand ... scope of this too much last minute ... > If we&`#39`;re removing the host api entirely, it&`#39`;s now not possible to tunnel/reverse-tunnel a service from the module container? > > I quite liked this feature, and I&`#39`;m not sure if we should remove it - though maybe it does genuinely belong somewhere else (e.g. under `Local` as in https://github.com/dagger/dagger/pull/6408). ... > **Review (approved):** > Happy to take this now, since it&`#39`;ll be good to remove the access to the host files for this release. > > But also, I want to make sure that https://github.com/dagger/dagger/pull/6535#issuecomment-1921051137 doesn&`#39`;t get lost, and that we have a way to restore this in the future. > > (ahhh, I&`#39`;ve realized we can do tunnels using the chainable `up` to do this) <title>Details on status of dagger.Host in SDK docs · Issue `#7998` · dagger/dagger</title> GitHub issue 7998 in dagger/dagger (link omitted to avoid creating a cross-reference) # Issue: dagger/dagger `#7998` - Repository: dagger/dagger | Automation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud | 16K stars | Go ## Details on status of dagger.Host in SDK docs - Author: [`@ghost`](https://github.com/ghost) - State: closed (completed) - Labels: area/sdk, area/sdk/python - Created: 2024-07-22T11:00:41Z - Updated: 2024-07-23T13:07:39Z - Closed: 2024-07-23T13:07:39Z ### What is the issue? When working on Python pipelines with Dagger, I frequently reference the [SDK&`#39`;s documentation](https://dagger-io.readthedocs.io/en/sdk-python-v0.12.1/), and it&`#39`;s a very helpful resource. During my work, I discovered the [dagger.Host object](https://dagger-io.readthedocs.io/en/sdk-python-v0.12.1/client.html#dagger.Host) and the [dagger.Client.host method](https://dagger-io.readthedocs.io/en/sdk-python-v0.12.1/client.html#dagger.Client.host), which suggested that these could be used to retrieve host information. However, I encountered an issue in practice where the following code snippet. ```python `@function` def get_host(self) -> dagger.Host: return dag.host() ``` throws the error: ``` AttributeError: module &`#39`;dagger&`#39`; has no attribute &`#39`;Host&`#39`; ``` I couldn&`#39`;t type hint the function since it doesn&`#39`;t recognize the existence of a `dagger.Host` type. After modifying the function to return a `dagger.Directory` to avoid type hint issues: ```python `@function` def get_host_dir(self) -> dagger.Directory: return dag.host().directory(&`#39`;.&`#39`;) ``` I encountered a similar error: ``` Function execution error: &`#39`;Client&`#39`; object has no attribute &`#39`;host&`#39`; ``` This led me to believe that the `host`-related stuff may have been removed from the SDK. Further research led me to this PR (`#6535`) which seems to be the answer to my question. Using the following code: ```python `@function` def get_host(self) -> dagger.Directory: return dag.current_module().source() ``` would now return that module&`#39`;s directory. If my understanding is correct, `Host` is a thing of the past and these are just leftovers in the documentation that weren&`#39`;t removed? I took a look at Go SDK docs and [Client.Host()](https://pkg.go.dev/dagger.io/dagger#Client.Host) is also listed there without any details on its removal on end-user side. I got an impression it&`#39`;s a thing I can use. Should the `Host`-related stuff be removed from the documentation, or at least be updated with a more detailed description and a redirect to `CurrentModule`? I could use and would appreciate more details on this in the documentation. --- ### Timeline **`@helderco`** commented · Jul 22, 2024 at 11:38am > That&`#39`;s just the **reference documentation**, it doesn&`#39`;t have the whole picture. It&`#39`;s expected that you rely more on the [Dagger docs](https://docs.dagger.io) for learning. In this case in particular, see [Execution Environment](https://docs.dagger.io/manuals/developer/execution-environment). > > To answer your question, `Client.host` is not deprecated, just not available in Dagger Modules, but still usable when not using Modules. **`@ghost`** commented · Jul 22, 2024 at 12:02pm · Author > I see, what would be other ways of using Dagger outside of Modules? I can think of sending GraphQL queries to the Dagger Engine, but is there something else other than that? So far, I was rather focused on development with the SDK and modules seemed to be the thing. **`@helderco`** commented · Jul 22, 2024 at 1:29pm > Some people haven&`#39`;t migrated to Modules yet. Running Dagger pipelines directly from the host is now considered an advanced/niche use case, but still allowed. Right now, the big downside to that is that it&`#39`;s not easy to interact with Modules yet. You can do it with raw GraphQL queries but you won&`#39`;t get generated client bindings for the Modules that you want to use (e.g., `dag.trivy()`). We plan on having this fixed though. > > Main advantage for this use …[truncated]

Citations:


🌐 Web query:

Dagger 0.21 module +defaultPath "." Directory input excludes .git files source filtering documentation

💡 Result:

Inspection citation: inspection_06a4c4479dfb57b9f3ae0f35216681f1

<source_evidence>

<title>Dagger 0.13: First-class Monorepo Support, Private Modules, a New CLI Command, and More | Dagger Blog</title> https://dagger.io/blog/dagger-0-13/ #### Pre-call filtering ... Dagger Functions filter the contents of directories they receive as arguments. Crucially, these filters are applied before the function is called. This leads to massive performance gains in monorepos, for two reasons: ... 1. Optimized uploads. ... the Dagger ... your function needs. The more files in your repository, the more drastic the ... 2. Better caching. Pre- ... filtering means pre-cache filtering: local files ... by your function ... will not invalidate its cache if they ... Both features - context directory and pre-call filtering - are used by annotating arguments to your function. Here is an example: ... Golang ``` func (m *Example) Example( // +defaultPath="/" // +ignore=[“.git”, “*.env”, “.github”] repo *dagger.Directory, // +defaultPath="." moduleDir *dagger.Directory, // +defaultPath=”/README.md” readme *dagger.File ) (...) {...} ``` ... ``` `@func`() async example( `@argument`({ defaultPath: "/", ignore: [“.git”, “*.env”, “.github”] }) repo: Directory, `@argument`({ defaultPath: "." }) moduleDir: Directory, `@argument`({ defaultPath: “/README.md”}) readme: File, ): any {...} ``` ... ``` `@function` async def example( self, repo: Annotated[dagger.Directory, DefaultPath("/"), Ignore([“.git”, “*.env”, “.github”])], moduleDir: Annotated[dagger.Directory, DefaultPath(".")], readmeFile: Annotated[dagger.File, DefaultPath("/README.md")] ) : ``` <title>Feat/context directory · Pull Request `#7744` · dagger/dagger</title> GitHub pull request 7744 in dagger/dagger (link omitted to avoid creating a cross-reference) This PR updates the `Function` and `FunctionArg` from our engine API to support `defaultPathFromContext` ... ```gql # Function withArg( """ If the argument is a Directory or File type, default to load path from context directory, relative to root directory. """ defaultPath String = "" ignore: [String!] # } ... # FunctionArg { """ If the argument is a Directory or File type, default to load path from context directory, relative to root directory. """ defaultPath: String! ignore: [String!] # } ``` ... - Update `Call` to load contextual values and insert it as input. - Add a `loadContextualArg` function that take the typedef and retrieve its contextual default value. - Add a function `loadContext` to load from `git` or `local` source the contextual path. ... This implements the spec designed in `#7647` For git: we load it from the context directory since it includes the whole repo. For local: we load it from `importLocal` with the specific directory specified so we never load the full repo expect for `/` ... - [x] The context directory is the git repository containing the module. If there is not git repository, the context is simply the module. - [x] Relative paths are relative to the current source file, scoped to the context directory for security - [x] Absolute paths are rooted in the context directory - [x] There is no limit to the number of directories which can have default values of this sort - [x] Optionally, directories can be filtered with a gitignore-style annotation ... - [x] Go using pragmas directive on `Directory` or `File` type ⌛ - [x] Typescript using `@argument({ defaultPath: "path", ignore: ["xx", "!xx"] })` ✅ ... ```typescript `@func`() build( `@argument`({ defaultPath:"./frontend/src" }) frontend: Directory, `@argument`({ defaultPath:"./backend/app/src" }) backend: Directory, `@argument`({ defaultPath: "./tools/builder.conf" }) buildConfig: File, ): Directory {} ``` ... 7-L ... > > I thought we were using default values? I might have missed (or forgotten) the last round of bikeshedding on that topic. > > I updated my view in https://github.com/dagger/dagger/issues/7647#issuecomment-2174570033: > > > [...] warming up to not using the default value because of that as it makes an overall simpler implementation, just sacrificing on DX for SDKs that support default values, but that can be improved later. > > --- > > > * [x] Typescript using `@context("path")` ⚡ to be tested once the engine changes are completed > > * [ ] Python using `@context("path")` ? To be confirmed by `@helderco` ⌛ > > We need to bikeshed on the `@context` name. > > In Python, this would have to be done using metadata annotation on the type: > > ```python > def build( > self, > backend: Annotated[ > dagger.Directory, > DefaultFromContext("../backend/app/src"), > Ignore(...), > ] > ) -> dagger.Directory: > ... > ``` ... > > `@TomChv` could you add example snippets of what that feature would look like, in the 3 main languages please? It would make it easier to discuss the DX tradeoffs > > I think it should look like this: > > **Go** > > ```go > func (app *App) Build( > // +default="./frontend/src" > frontend *Directory, > // +default="./backend/app/src" > backend *Directory, > // +default="/tools/builder.conf" > buildConfig *File, > ) *Directory {} > ``` > > **Typescript** > > ```typescript > `@func`() > build( > `@context`("./frontend/src") frontend: Directory, > `@context`("./backend/app/src") backend: Directory, > `@context`("./tools/builder.conf") buildConfig: File, > ): Directory {} > ``` > > **Python** > > Done by Helder above > > > ```py…[truncated] <title>feat/context directory (`#7744`) · 9c2c03f · dagger/dagger</title> https://github.com/dagger/dagger/commit/9c2c03f19d860a1c50f39340613ee4910b5d877e Add `defaultPath` metadata to an argument to make it contextual. This is also usable on `Directory` & `File` for now. ... This will let the Engine load the artifact before actually callling the function which simplify the caching and make the parameter optional. ... This is extra useful for redondant parameter such as source code or ... config files. ... Path can be either relative or absolute: ... - If absolute: load from the context dir (.git) - If relative: load from the root dir (dagger.json) ... Add `ignore` metadata to an argument to include or exclude specified files. The ignore patterns follow `.gitignore` convention so prefixing a path with `!` will actually include the file. ... spec *func ... Code = append(argOptsCode, Id("DefaultValue").Op(":").Id("dagger").Dot("JSON").Call(Lit(argSpec.defaultValue ... } + if argSpec.defaultPath != "" { + argOptsCode = append(argOptsCode, Id("DefaultPath").Op(":").Lit(argSpec.defaultPath)) + } ... + ignores ... + defaultPath := "" + if v, ok := pragmas["defaultPath"]; ok { + defaultPath = v + if strings.HasPrefix(v, `"`) && strings.HasSuffix(v, `"`) { + defaultPath = v[1 : len(v)-1] + } + + optional = true // If defaultPath is set, the argument becomes optional + } ... []string{} ... , ok := pragmas["ignore"]; ... ("ignore pragma &`#39`;% ... ps *parseState) ... (field *types. ... docComment string, lin ... @@ -326,4 +358,13 @@ type paramSpec struct { // parent is set if this paramSpec is nested inside a parent inline struct, // and is used to create a declaration of the entire inline struct parent *paramSpec + + // Only applies to arguments of type File or Directory. + // If the argument is not set, load it from the given path in the context directory + defaultPath string + + // Only applies to arguments of type Directory. + // The ignore patterns are applied to the input directory, and + // matching entries are filtered out, in a cache-efficient manner. + ignore []string } ... +func (t *Test) Dirs( + ctx context.Context, + + // +defaultPath="/" + root *dagger.Directory, + + // +defaultPath="." + relativeRoot *dagger.Directory, +) ([]string, error) { + res, err := root.Entries(ctx) + if err != nil { + return nil, err + } + relativeRes, err := relativeRoot.Entries(ctx) + ... { + return ... , err ... } + ... res, relativeRes...), ... +func (t *Test) DirsIgnore( + ctx context.Context, + + // +defaultPath="/" + // +ignore=["!backend", "!frontend"] + root *dagger.Directory, + + // +defaultPath="." + // +ignore=["dagger.json", "LICENSE"] + relativeRoot *dagger.Directory, +) ([]string, error) { + res, err := root.Entries(ctx) + if err != nil { + return nil, err + } + relativeRes, err := relativeRoot.Entries(ctx) + if err != nil { + return nil, err + } + return append(res, relativeRes...), nil +} ... +func (t *Test) RootDirPath( + ctx context.Context, + + // +defaultPath="/backend" + backend *dagger.Directory, + + // +defaultPath="/frontend" + frontend *dagger.Directory, + + // +defaultPath="/ci/dagger/sub" + modSrcDir *dagger.Directory, +) ([]string, error) { + backendFiles, err := backend.Entries(ctx) + if err != nil { + return nil, err + } + frontendFiles, err := frontend.Entries(ctx) + if err != nil { + return nil, err + } + modSrcDirFiles, err := modSrcDir.Entries(ctx) + if err != nil { + return nil, err + } + + res := append(backendFiles, append(frontendFiles, modSrcDirFiles...)...) + + return res, nil +} ... ctx context.Context ... // +defaultPath="./dagger/sub" + modSrcDir *dagger.Directory, + + // +defaultPath="../backend" + backend *dagger.Directory, +) ... , error) { + modSrcDir ... , err := modSrcDir.Entries(ctx) + if err != nil { + return ... , err + } + backendFiles, err := backend.Entries(ctx) + if err != nil { …[truncated] <title>core/integration/module_path_inputs_test.go</title> https://github.com/dagger/dagger/blob/c7d72b6c/core/integration/module_path_inputs_test.go // These tests cover module arguments that receive filesystem or Git content. // They verify how `+defaultPath`, `+ignore`, `.gitignore`, and explicit filters // shape Directory, File, and GitRepository inputs before module code sees them. // ... func (t *Test) Dirs( ctx context.Context, // +defaultPath="/" root *dagger.Directory, // +defaultPath="." relativeRoot *dagger.Directory, ) ([]string, error) { res, err := root.Entries(ctx) if err != nil { return nil, err } relativeRes, err := relativeRoot.Entries(ctx) if err != nil { return nil, err } return append(res, relativeRes...), nil } ... func (t *Test) DirsIgnore( ctx context.Context, // +defaultPath="/" // +ignore=["**", "!backend", "!frontend"] root *dagger.Directory, // +defaultPath="." // +ignore=["dagger.json", "LICENSE"] relativeRoot *dagger.Directory, ) ([]string, error) { res, err := root.Entries(ctx) if err != nil { return nil, err } relativeRes, err := relativeRoot.Entries(ctx) if err != nil { return nil, err } return append(res, relativeRes...), nil } ... func (t *Test) RootDirPath( ctx context.Context, // +defaultPath="/backend" backend *dagger.Directory, // +defaultPath="/frontend" frontend *dagger.Directory, // +defaultPath="/ci/dagger/sub" modSrcDir *dagger.Directory, ) ([]string, error) { backendFiles, err := backend.Entries(ctx) if err != nil { return nil, err } frontendFiles, err := frontend.Entries(ctx) if err != nil { return nil, err } modSrcDirFiles, err := modSrcDir.Entries(ctx) if err != nil { return nil, err } res := append(backendFiles, append(frontendFiles, modSrcDirFiles...)...) return res, nil } ... func (t *Test) RelativeDirPath( ctx context.Context, // +defaultPath="./dagger/sub" modSrcDir *dagger.Directory, // +defaultPath="../backend" backend *dagger.Directory, ) ([]string, error) { modSrcDirFiles, err := modSrcDir.Entries(ctx) if err != nil { return nil, err } backendFiles, err := backend.Entries(ctx) if err != nil { return nil, err } return append(modSrcDirFiles, backendFiles...), nil } ... ctx context.Context, ... defaultPath="/ci/ ... " license * ... .File, // +defaultPath="./dagger/sub ... " index *dagger.File, ) ... string, error) { licenseName ... err := license ... Name(ctx) if err != nil { return ... , err } indexName ... err := index ... Name(ctx) if err != nil { return nil, err } return []string{licenseName, indexName}, nil } ... out, ... frontend/\ndagger/\ ... " switch tc ... typescript": ... func (ModuleSuite) TestDefaultPathAndIgnoreUseRemoteModuleSource(ctx context.Context, t *testctx.T) { c := connect(ctx, t) remoteModule := c.Directory(). WithNewFile("source.txt", "module source"). WithNewFile("filtered/keep.txt", "module keep"). WithNewFile("filtered/drop.txt", "module drop"). WithNewFile("dagger.json", `{"name":"reader","sdk":{"source":"go"}}`). WithNewFile("main.go", `package main ... // ReadDefaultFile proves a File +defaultPath is resolved from this module source. func (m *Reader) ReadDefaultFile( ctx context.Context, // +defaultPath="/source.txt" source *dagger.File, ) (string, error) { return source.Contents(ctx) } ... // ReadDefaultDirectoryFile proves a Directory +defaultPath is resolved from this module source. func (m *Reader) ReadDefaultDirectoryFile( ctx context.Context, // +defaultPath="/filtered" filtered *dagger.Directory, ) (string, error) { return filtered.File("keep.txt").Contents(ctx) } ... // ListIgnoredDefaultDirectory proves +ignore applies to the defaultPath directory from this module source. func (m *Reader) ListIgnoredDefaultDirectory( ctx context.Context, // +defaultPath="/filtered" // +ignore=["drop.txt"] filtered *dagger.Directory, ) ([]strin…[truncated] <title>+ignore="git": optionally apply gitignore to a directory argument</title> GitHub issue 11317 in dagger/dagger (link omitted to avoid creating a cross-reference) # +ignore="git": optionally apply gitignore to a directory argument - State: closed - Author: shykes - Created: 2025-10-28T21:45:42Z - Updated: 2026-03-25T05:18:31Z - Repository: dagger/dagger - Number: `#11317` --- Dagger can natively load .gitignore and apply its rules to filter host directories pre-upload. This feature is disabled by default, and can be enabled as an argument to `Host.directory()`. But, it can NOT be enabled by a function to specify pre-call filtering on its own arguments... In other words, we are missing +gitignore (or +ignore="git") Perhaps this is easier to implement by piggypacking on an existing directive (`+ignore`) which is already supported by all SDKs? But will SDKs allow passing a string instead of an array? ## Timeline - Renamed from "+gitignore: optionally apply gitignore to a directory argument" to "+ignore="git": optionally apply gitignore to a directory argument" **vito** commented on 2025-10-28T22:58:23Z: > > Perhaps this is easier to implement by piggypacking on an existing directive (`+ignore`) which is already supported by all SDKs? But will SDKs allow passing a string instead of an array? > > I see the appeal, but I suspect supporting two types will end up being just a _different kind_ of change to make to each SDK. > > In defense of adding a pragma, it should be a well-beaten path by now, the only inventive thing really is how to "when in rome" it in each SDK. It&`#39`;s laborious for sure, though. > > But if we want, we _could_ sidestep it by adding a special syntax to the ignore rules themselves - then it&`#39`;s always `[]string`: > > ```go > // A directory that ignores `.dagger` and whatever&`#39`;s specified by `.gitignore`. > // > // +ignore=[".dagger", "+.gitignore"] > src *dagger.Directory, > ``` > > We already handle a `!` prefix so handling `+` or some other uncommon path prefix symbol seems OK to me. > > (More to bikeshed, but I&`#39`;ll pause here in case twisting whatever this pseudostandard is is unpalatable.) **shykes** commented on 2025-10-29T18:51:28Z: > `@vito` I think it&`#39`;s safer to have a separate pragma. It&`#39`;s true that we already have `!foo` as a precedent, and `+foo` could make sense to mean "include ignores from this other file", but: > > 1. There would be *some* confusion from people thinking it means "definitely include this file" or some other interpretation > 2. We would need to support multiple ignore file formats under the same `+` directive: `.gitignore`, but in the future `.dockerignore`, and perhaps a dagger-specific format that simply is a json serialization of our own directives? That feels a little too much. > 3. (as mentioned by `@jedevc` in discord). "apply git ignore" is not exactly the same as "apply this gitignore file", as there might be several cascading files etc. so there&`#39`;s an impedance mismatch. > > > TLDR I think `+gitignore` is the safe choice - vito mentioned - vito subscribed - jedevc mentioned - jedevc subscribed **Neirda24** commented on 2025-11-24T20:01:58Z: > Hi. Jumping in here to give a few other usecases. My example are based on PHP needs but I think it can apply to any other languages. > > 1. Yes ignoring based on .gitignore is a must have... BUT we can have multiple .gitignore in a given repository so the directory object should be able ot ignore everything from any .gitignore file. > 2. Given we are working closely to docker features, supporting `.dockerignore` would seem appropriate and relevant. Especially for easy migration. WDYT ? > 3. Any custom file could be defined as an "ignore" list and I think it should opt in to have several ignore files. > 4. In many cases we want to "include" instead of ignore. Because it requires less maintenance. For php-cs-fixer for example we apply it …[truncated]

Citations:


Sensitive Data Exposure

Reachability: External
Exploitability: Trivial
CWE: CWE-522 — Insufficiently Protected Credentials

Disable persisted checkout credentials before running Dagger.

Ci.src uses +defaultPath=".", so Dagger passes the repository context to the module without excluding .git. Pull-request-controlled Dagger code can read src.File(".git/config") and exfiltrate the checkout token. Dagger host access is not required.

contents: read prevents write operations but still exposes a bearer token with repository-content read access.

Suggested fix
         uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        with:
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.30.0)

[warning] 25-26: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


- name: Build + test (dagger call ci)
uses: dagger/dagger-for-github@27b130bf0f79a7f6fbbbe0fbca6760dc9bb40a77 # v8.4.1
with:
version: "0.21.9"
verb: call
args: ci
15 changes: 10 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,19 @@ implementing the `pkg/bmcdev` interface and reuses `pkg/` and `core/` unchanged.

## Build & test

Dagger is the only build interface; it fetches the TamaGo fork, the shared
Kyanite modules and the tamago-go compiler release from public GitHub, so builds
need no local checkouts. Override any source with `--<dir>` for local work.

```sh
make build # TamaGo ELF -> bin/cairn.elf (needs TAMAGO set to a tamago-go binary)
make test # host unit tests (user_linux tag)
dagger call ci # reproducible CI (build + test)
dagger call build export --path ./bin # TamaGo ELF -> bin/cairn.elf
dagger call test # host unit tests (user_linux tag)
dagger call ci # build + test (what CI runs)
```

Compiles with `GOOS=tamago GOARCH=arm64`. The AST2700 SoC/board support comes
from a TamaGo fork wired in via a local (git-ignored) `go.work`.
Compiles with `GOOS=tamago GOARCH=arm64`. The A1 SPI image is
`dagger call image --bmc-pb <prebuilts> --silicon a1`; the A2 image (vendor-signed
FLSH container, not reproducible in-container) is `tools/a2/gen-a2-image.sh`.

## Conventions

Expand Down
162 changes: 0 additions & 162 deletions Makefile

This file was deleted.

30 changes: 23 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,33 @@ Cairn follows the same embedded-friendly conventions as vein:

## Build

The AST2700 arm64 SoC/board support lives in a TamaGo fork that is not yet
upstream. Until it lands, `go.work` redirects `github.com/usbarmory/tamago` to
that fork (`../tamago`).
Everything is built with [Dagger](https://dagger.io), which fetches the TamaGo
fork (AST2700 support), the shared Kyanite modules and the tamago-go compiler
release from public GitHub — so the whole flow builds from public sources with
no local checkouts and no toolchain setup beyond Dagger:

```bash
make build # AST2700 DC-SCM EVB ELF → bin/cairn.elf
make test # host unit tests (user_linux tag)
dagger call build export --path ./bin # AST2700 DC-SCM EVB ELF → bin/cairn.elf
dagger call test # host unit tests (user_linux tag)
dagger call ci # build + test (what CI runs)
```

Requires the TamaGo compiler (`TAMAGO=/path/to/tamago-go/bin/go`) and
`llvm-readelf`.
Pass `--<dir>` (e.g. `--core ../core`, `--tamago ../tamago`) to build against a
local checkout instead of the public default.

### Full SPI flash image

```bash
# A1: fully reproducible, in-container. --bmc-pb supplies the vendor prebuilts
# (Caliptra FW, DDR training, DP FW), which are not redistributable.
dagger call image --bmc-pb ../bmc-pb --silicon a1 export --path ./out

# A2: FLSH container + vendor-signed ATMN SoC manifest. The manifest signing
# uses the vendor cptra_imgtool and is not reproducible in-container, so it runs
# on the host — see tools/a2/gen-a2-image.sh.
CPTRA_IMGTOOL=../cptra_imgtool PREBUILT=/path/to/a2-prebuilts \
tools/a2/gen-a2-image.sh
Comment on lines +89 to +90

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document the host TamaGo requirement for A2.

tools/a2/gen-a2-image.sh directly runs ${TAMAGO:-tamago}. A user who follows this command after the stated Dagger-only setup gets tamago: command not found. Document the required host TamaGo compiler and the TAMAGO override.

```

## Module

Expand Down
2 changes: 1 addition & 1 deletion dagger.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cairn",
"engineVersion": "v0.21.6",
"engineVersion": "v0.21.9",
"sdk": {
"source": "go"
},
Expand Down
2 changes: 1 addition & 1 deletion tools/a2/cairn-a2-manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ mldsa_priv_key = "own-man-mldsa-priv-key.bin"

[image_runtime_list]
caliptra_file = "caliptra-fw.bin"
# MCU runtime (BootMCU FMC): our aspeed-mcu-runtime Rust BootMCU, built for A2
# MCU runtime (BootMCU FMC): our mcu-runtime Rust BootMCU, built for A2
# (linked at 0x14B80000) by gen-a2-image.sh. Override with MCU_RUNTIME_BIN to
# use a prebuilt binary (e.g. vendor Zephyr).
mcu_file = "ast2700-mcu-runtime.bin"
Expand Down
41 changes: 26 additions & 15 deletions tools/a2/gen-a2-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,30 @@ mkdir -p "$OUT" "$STAGE"
rm -f "$OUT/$IMAGE_NAME"

echo "==> 1/4 build cairn CA35 payload"
# Forward VIDEO=1 (framebuffer console) and FACETUI=1 (embed the facet SPA).
CAIRN_TAGS=""
if [ -n "${FACETUI:-}" ]; then
CAIRN_TAGS="facetui"
fi
# Cross-compile the CA35 payload ELF with the host TamaGo compiler. The CA35
# cores are Cortex-A35 (ARMv8.0-A, no FEAT_LSE), so pin GOARM64=v8.0 to keep the
# compiler from emitting large-system atomics (which trap on this core). The
# payload links at the CA35-view DRAM text base (0x404000000). VIDEO=1 compiles
# in the DisplayPort framebuffer console; FACETUI=1 embeds the facet SPA.
build_payload() {
( cd "$CAIRN" && GOOS=tamago GOARCH=arm64 GOARM64=v8.0 \
GOOSPKG=github.com/usbarmory/tamago GOTOOLCHAIN=local \
"$TAMAGO" build -trimpath -tags "$1" \
-ldflags "-T 0x404000000 -R 0x1000" -o "$2" ./target/ast2700-dcscm-evb )
}
if [ "$DIAG" = "1" ]; then
DIAG_EXTRA="$CAIRN_TAGS"
[ "$DIAGDMA" = "1" ] && DIAG_EXTRA="${DIAG_EXTRA:+$DIAG_EXTRA,}flashdiagdma"
[ "$DIAGWRITE" = "1" ] && DIAG_EXTRA="${DIAG_EXTRA:+$DIAG_EXTRA,}flashdiagwrite"
echo " DIAG build: make flashdiag TAGS_EXTRA=$DIAG_EXTRA"
( cd "$CAIRN" && TAMAGO="$TAMAGO" TAGS_EXTRA="$DIAG_EXTRA" make flashdiag )
# Read-only FMC/SPI-NOR hardware diagnostic payload (flashdiag tag).
TAGS="ast2700dcscm,linkcpuinit,flashdiag"
[ "$DIAGDMA" = "1" ] && TAGS="$TAGS,flashdiagdma"
[ "$DIAGWRITE" = "1" ] && TAGS="$TAGS,flashdiagwrite"
[ -n "${FACETUI:-}" ] && TAGS="$TAGS,facetui"
echo " DIAG build: tags=$TAGS"
build_payload "$TAGS" "$PAYLOAD_ELF"
else
( cd "$CAIRN" && TAMAGO="$TAMAGO" VIDEO="${VIDEO:-}" TAGS_EXTRA="$CAIRN_TAGS" make build )
TAGS="linkcpuinit,ast2700dcscm"
[ "${VIDEO:-}" = "1" ] && TAGS="$TAGS,ast2700video,linkprintk"
[ -n "${FACETUI:-}" ] && TAGS="$TAGS,facetui"
build_payload "$TAGS" "$PAYLOAD_ELF"
fi
llvm-objcopy -O binary "$PAYLOAD_ELF" "$STAGE/cairn.payload.bin"

Expand Down Expand Up @@ -136,17 +147,17 @@ for f in caliptra-fw.bin \
done

# The MCU runtime (BootMCU FMC, FLSH id 3). By default we build our own
# aspeed-mcu-runtime Rust BootMCU for A2 from source. A2 links the FMC at GSRAM
# mcu-runtime Rust BootMCU for A2 from source. A2 links the FMC at GSRAM
# base 0x14B80000 (the A2 ROM loads it there, with no ASTH header); the A1
# default links at 0x14B80A00 and faults the instant the A2 ROM jumps to it —
# the firmware loads (Ff=0000) and is entered (J=0000) but every absolute
# address is off by 0xA00, so nothing prints. embassy-aspeed's build.rs selects
# the A2 layout (link/ast2700-bootmcu-a2.x) when AST2700_BOOTMCU_A2 is set.
#
# Set MCU_RUNTIME_BIN to override with a prebuilt binary (e.g. vendor Zephyr, or
# a pre-built FMC); set MCU_RUNTIME_SRC to point at a different aspeed-mcu-runtime
# a pre-built FMC); set MCU_RUNTIME_SRC to point at a different mcu-runtime
# checkout.
MCU_RUNTIME_SRC="${MCU_RUNTIME_SRC:-$CAIRN/../aspeed-mcu-runtime}"
MCU_RUNTIME_SRC="${MCU_RUNTIME_SRC:-$CAIRN/../mcu-runtime}"
if [ -n "${MCU_RUNTIME_BIN:-}" ]; then
echo " MCU runtime (prebuilt): $MCU_RUNTIME_BIN"
cp "$MCU_RUNTIME_BIN" "$STAGE/ast2700-mcu-runtime.bin"
Expand All @@ -159,7 +170,7 @@ elif [ -d "$MCU_RUNTIME_SRC/app-rot" ]; then
llvm-objcopy -O binary "$MCU_ELF" "$STAGE/ast2700-mcu-runtime.bin"
else
echo "ERROR: no MCU runtime: set MCU_RUNTIME_BIN to a prebuilt FMC, or" >&2
echo " MCU_RUNTIME_SRC to an aspeed-mcu-runtime checkout to build ours." >&2
echo " MCU_RUNTIME_SRC to an mcu-runtime checkout to build ours." >&2
exit 1
fi

Expand Down
Loading