Code Monkey home page Code Monkey logo

gittuf's Introduction

gittuf logo

OpenSSF Best Practices Build and Tests (CI)

gittuf provides a security layer for Git using some concepts introduced by The Update Framework (TUF). Among other features, gittuf handles key management for all developers on the repository, allows you to set permissions for repository branches, tags, files, etc., lets you use new cryptographic algorithms (SHA256, etc.), protects against other attacks Git is vulnerable to, and more — all while being backwards compatible with GitHub, GitLab, etc.

gittuf is a sandbox project at the Open Source Security Foundation (OpenSSF) as part of the Supply Chain Integrity Working Group.

Current Status

gittuf is currently in alpha. It is NOT intended for use in a production system or repository. Contributions are welcome, please refer to the contributing guide. Some of the features listed above are being actively developed, please refer to the roadmap and the issue tracker for more details.

Installation & Get Started

See the get started guide.

gittuf's People

Contributors

adityasaky avatar datosh avatar dependabot[bot] avatar inosmeet avatar jsoref avatar justincappos avatar naveensrinivasan avatar neilnaveen avatar patzielinski avatar reza-curtmola avatar spectre10 avatar webchick avatar wlynch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gittuf's Issues

Roadmap: Integrate with broader ecosystem

gittuf ought to integrate with other Git tools where possible. Some examples:

  1. Integrate with GitHub / GitLab to enforce those repository policies using gittuf
  2. Integrate with GitHub / GitLab API to support pull request / merge request workflows in the RSL
  3. Support attestations (#85) from these platforms or from dedicated tools like Gerrit, git-appraise

Add docstrings

Most of the APIs are currently not documented clearly. Addition of docstrings would be fantastic, especially for rendering on pkg.go.dev.

[Bug]: Installing using `go install` will fail due to the replace directive in go.mod

What happened?

go install doesn't work with a replace directive in go.mod. It's possible that this doesn't affect goreleaser's builds (#146) though we need to validate that assumption. If we do have binaries from goreleaser, we can update the docs to dislallow go install in the short term and use the pre-built binaries in the demo's CI.

Also see: https://github.com/gittuf/demo/actions/runs/6637693850/job/18032523935?pr=2

Relevant log output

$ go install github.com/gittuf/gittuf@latest
go: downloading github.com/gittuf/gittuf v0.0.0-20231025013735-a376de9ab7af
go: github.com/gittuf/gittuf@latest (in github.com/gittuf/[email protected]):
        The go.mod file for the module providing named packages contains one or
        more replace directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Bug]: clone does not handle slashes at the end of repository path.

What happened?

the Clone func added in #134 does not handle slashes at the end of repository path.

func Clone(ctx context.Context, remoteURL, dir, initialBranch string) (*Repository, error) {
	if dir == "" {
		// FIXME: my understanding is backslashes are not used in URLs but I haven't dived into the RFCs to check yet
		split := strings.Split(strings.TrimSpace(strings.ReplaceAll(remoteURL, "\\", "/")), "/")
		dir = strings.TrimSuffix(split[len(split)-1], ".git")
	}
	..
	..
	if err := os.Mkdir(dir, 0755); err != nil {
		return nil, errors.Join(ErrCloningRepository, err)
	}
	..
}

Here, if we provide slashes at the end of remoteURL, split[len(split)-1] results in an empty string. Consequently, dir also results in an empty string. Afterwards, when dir is provided to Mkdir, it results in an error.

Relevant log output

$ ./gittuf clone https://github.com/gittuf/ci-demo.git/
Error: unable to clone repository
mkdir : no such file or directory
Usage:
  gittuf clone [flags]

Flags:
  -b, --branch string   Specify branch to check out
  -h, --help            help for clone

Code of Conduct

  • I agree to follow this project's Code of Conduct

[Bug]: Improve Sorting of Commits in GetCommitsBetweenRange Function

What happened?

This issue addresses the sorting of git commits in the GetCommitsBetweenRange in log.go function by occurrence order. addresses this FIXME

// FIXME: we should ideally be sorting this in the order of occurrence

Proposed Changes:

A potential solution to this issue is to perform a depth-first search (DFS) from the bottom to the top of the commit tree. Since commits form a directed acyclic graph (DAG), we can infer that each parent of a given commit must have occurred before the commit itself. Therefore, each tree level has occurred only after the previous level.

Implementation Details:

We can create a map with the commit (a "node" in the git DAG) as the key and the occurrence (or depth in the git DAG) as the value. We can then traverse from each node to the "root" (or first commit) to determine the occurrence/depth.

To optimize this process, we can cache the depth for nodes visited while finding the root node. This cache will also serve as the result since it will contain a key for each node and a value for its depth. If we encounter a node that we have already visited and is in the cache, we can simply return the cached result.

In the case of a git DAG, where a node can have multiple parents, we should ensure that we are picking the path to the root that takes the longest. This is because the longest path will provide the most accurate depth information.

Concerns & Limitations:

However, this approach may not be efficient for large repositories with tens of thousands of nodes, as the runtime would be O(n), where n is the size of the tree.  The nodes we are sorting might often be clustered in a small subtree, making this approach inefficient.

A lowest common ancestor (LCA) solution, where we compare the depths of the nodes to the LCA between all nodes to be sorted, would not work. This is because git's commit history is a DAG, not a tree. For merge commits, different parent commits could lead to entirely different "subtrees", meaning the depth from the LCA to each node would not accurately reflect the actual occurrence of the node.

This is the best solution I could come up with, given the constraints. If there is a more efficient approach, I would appreciate any suggestions.

// Pseudocode for the proposed changes
function getDepth(node, cache) {
	if node in cache {
		return cache[node]
	}
	
	maxDepth = 0
	for each parent of node {
		depth = getDepth(parent, cache)
		if depth > maxDepth {
			maxDepth = depth
		}
	}
	
	cache[node] = maxDepth + 1
	return cache[node]
}
	
function sortCommitsByOccurrence(commits) {
	cache = map[node]int
	for each commit in commits {
		getDepth(commit, cache)
	}
	
	sort commits by depth in cache
}

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Use annotations in RSL queries and policy verification

RSL annotations are distinct from regular entries in that they apply to other RSL entries. An annotation can also be marked as "skip" to indicate the referred RSL entries have been revoked. While it's possible to record RSL annotations, they're largely not used in the RSL package, nor in the policy package.

This is also a bug because unexpected annotations right now can lead to panics, crashing gittuf.

Settle terminology for RSL entries

The RSL can store two types of objects: an entry and an annotation. Unfortunately, we use the word "entry" in an abstract sense to refer to either of those two types. Some examples:

  • the EntryType interface
  • GetEntry which returns the object in the RSL for the specified ID, so this can be either an Entry or an Annotation
  • other APIs

I suggest we use the word "record", possibly as a replacement for the abstract use of the word "entry". I can also see an argument to swap them around, where "entry" is generic and the type that has a ref and target ID becomes a "record". Once this terminology is settled, it should be a fairly easy, if noisy, PR to rename the corresponding APIs. The specification can also be updated at the same time to reflect the change, I foresee a smaller diff there.

Roadmap: Dogfood gittuf

As noted in the gittuf roadmap, we must start using gittuf to protect the gittuf source repository. To do so, we need to consider the following things:

  1. Policies: what policies do we enable for the repository? Given that this is an open source project with external contributors, I suggest we start with a simple branch protection rule on main that requires a maintainer to have merged some change.
  2. Verification points: we ought to run gittuf verification in CI using the GitHub action that provisions gittuf. We also want to distribute this verification so I propose we gittuf maintainers run verification whenever we pull in the latest changes to the repository. This will get simpler with #220 and #158.
  3. RSL entry creation: we don't want to move away from GitHub's PRs for user contributions. For a single policy protecting main we only really need RSL entries for that branch. As a start, we could move only merges off the GitHub web UI so RSL entries are signed by the maintainers, but this will not scale. Along the way, I think we'll be able to flesh out how to align RSL entry creation with the GitHub UI, perhaps using a CI job that authenticates using Sigstore or signs an entry after authenticating the action using the GitHub API.

Add support for syncing gittuf namespaces

As gittuf maintains additional namespaces (refs/gittuf/{policy,reference-state-log}, the client must include functionality to sync these states with a user selected remote.

[Bug]: RSL doesn't correctly support tags

What happened?

Tags can be recorded in the RSL but verification workflows error out because RSL entries are expected to point to commits.

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

gittuf <-> gitsign attestation compatibility

Add a description

Context: #170

We should look into gittuf + gitsign attestation compatibility.

. gittuf gitsign
ref refs/gittuf/attestations refs/attestations/commits
refs/attestations/trees
...
attestation path refs/heads/main/a-b a/sbom.spdx.sig

Relevant log output if the discussion pertains to existing gittuf functionality

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Implement Reference State Log (RSL)

As discussed in #13 and defined in https://github.com/adityasaky/gittuf/blob/main/docs/specification.md, we want gittuf to implement a reference state log. Also see: https://www.usenix.org/conference/usenixsecurity16/technical-sessions/presentation/torres-arias

The RSL is stored at refs/gittuf/reference-state-log and entries are created for each push action. At any point, the RSL refspec points to a commit corresponding to the latest entry. The commit message includes the target ref and its new location (SHA-1 identifier) in a parse-able format.

[Bug]: Failed while running tests

What happened?

=== RUN TestVerifyCommitSignature
=== RUN TestVerifyCommitSignature/use_gpg_signed_commit_with_gitsign_key
commit_test.go:115:
Error Trace: /Users/naveen/go/src/github.com/naveensrinivasan/gittuf/internal/gitinterface/commit_test.go:115
Error: Target error should be in err chain:
expected: "incorrect key provided to verify signature"
in chain: "unable to verify Sigstore signature\ninitializing tuf: unable to initialize client, local cache may be corrupt: tuf: error unmarshalling key: invalid PEM value"
Test: TestVerifyCommitSignature/use_gpg_signed_commit_with_gitsign_key
--- FAIL: TestVerifyCommitSignature (0.03s)
--- FAIL: TestVerifyCommitSignature/use_gpg_signed_commit_with_gitsign_key (0.02s)

FAIL

Process finished with the exit code 1

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Expected behaviour of `state.Verify` when no Targets metadata is found

First raised in #37 (comment).

Currently, state.Verify() returns successfully if the top level targets role (same for delegated roles) is missing after verifying the root envelope's signatures. This is designed to support initial states where a root role may exist but no policies yet. We need to revisit how to handle this check going forward.

It's an issue if an attacker is able to modify the policy state of some copy of the repository to remove targets metadata. But for this, they need to be authorized to sign the RSL entry for the policy namespace. Also, future namespace specific verification workflows will error out if no policy metadata is found so this check may be redundant (not that redundancy is bad).

policies on paths that are not in the tree or missing

Per discussion in #4 (comment), I started investigating if it would be possible to use .git/hooks and apply policies on contest of that directory.

I've played around a bit and had a look at the code. It appears that at the moment policies can be defined on any kind of path pattern, and delegation to files outside the repo can be added, like ../foo and /foo don't get rejected. I am not sure about this behaviour, but I'm still a novice to TUF, so find it hard to judge.

In terms of how the code works, what is not clear to me is where git: and file: prefixes are handled, I don't seem to see parsing of these in the code, and TUF spec talks about PATHPATTERN without any such prefixes.

With that in mind, I also found that policy verification logic is reliant on lists of files that git provided, e.g.:

paths, err := gitinterface.GetFilePathsChangedByCommit(repo, commit)

So if I can add a policy for a file that is not in the tree, it will never be applied until the file does get checked in. This seems a little bit interesting if you consider e.g. unchecked work-in-progress files. I do wonder where this leads, perhaps there should be a way to define a policy that prevents a working tree with unchecked files from ever passing verification.
Also, if I do add a policy for a file that doesn't exist, should policy verification actually fail until that file gets checked in?

More generally, should there be a way to prevent certain paths, branches or tags being added at all?

gittuf <-> Git command compatibility

To improve gittuf's UX (#4), the CLI must provide some command compatibility with Git itself. This would allow users to use gittuf as a drop-in replacement for Git in common workflows such as syncing with remote repositories.

This is complementary to #158, where gittuf installs the right hooks to perform gittuf-specific actions for a repository. There, the user has gittuf installed but does not invoke it directly most of the time.

gittuf pull

Similar to git pull, gittuf pull must fetch changes and merge them into the local copy of the branch. In addition to the standard git workflow, gittuf pull must also fetch the remote RSL and verify the target branch of the pull. Note that in fetching the RSL, the gittuf policy namespace may need to be fetched too. See https://github.com/gittuf/gittuf/blob/main/docs/design-document.md#rslfetch-receiving-remote-rsl-changes for information on reconciling RSL divergence.

gittuf push

gittuf push must first fetch the remote RSL and reconcile any divergence in the target branch. This must be repeated until the remote and local RSLs match (once again, the policy namespace may also need to be updated based on what the RSL shows). Next, a new RSL reference entry must be created for the branch being pushed. gittuf verification must follow, to ensure the RSL entry is valid. If not, the entry must be deleted. If verification passes, the target branch and the RSL must be pushed to the remote.

Policy / rule examination interface

gittuf currently does not have subcommands to examine a policy / rules. If a user wants to inspect what policies are applicable for some state, they have to manually examine the different envelopes (decoding the payloads in the process) tracked at refs/gittuf/policy. As @errordeveloper points out in #4

One low-hanging fruit seems to be gittuf policy {list-rules,show-rule}. As a newbie, I was surprised that there isn't a way to see what policies are already defined.

How should gittuf invoke Git?

NOTE: This issue has been updated since it was originally created to reflect gittuf updates.

gittuf uses go-git for interactions with the underlying repository except for identifying the signing key configured in the user's git config. As go-git and the git binary do not have 100% feature parity and may drift over time (or go-git's development / maintenance may cease), we must implement an abstract interface for git interactions that can use go-git or a git binary.

We have some of this in the gitinterface package. By enumerating interactions with a git repository, we can create internal APIs that can use either go-git or the git binary. Also, the sooner we make this switch, the fewer interactions we'll have to clean up.

Original issue gittuf's CLI is designed to be a wrapper around Git's default CLI. As such, it currently shells out to the git binary installed on the system to execute certain actions. We need to confirm this makes sense and we have a clear separation of where we invoke the pre-installed git binary and where we use go-git.

Release v0.1.0

This issue is a tracker of things we need to implement before we can tag v0.1.0.

  • Support verifying RSL states (#62)
  • Support file policies (#82)
  • Add syncing functionality to push/pull refs/gittuf/* between remotes (#56)
  • verify-commit and verify-tag functionality (#15)

gittuf User Experience

The gittuf CLI provides "low level" commands but we need to build in some "high level" workflows for users to use 99% of the time. This issue is to discuss what these workflows look like and their UX.

Improve verification tests in the policy package

The policy package implements verification functions for RSL entries and commit signatures. However, not all behavior is well tested, in part because of how the test repositories are setup. The package uses helpers like createTestStateWithOnlyRoot and createTestStateWithPolicy to set up policy states that can be used during testing. These are not amenable for creating a variety of policy states to test edge cases, especially around key revocation events.

Fix sigstore integration and testing

#72 introduced gitsign verification support in gittuf using TUF's TAP-18. However, there's work to be done in testing the gitsign support.

  1. It might be possible to prune the dependency graph by switching from cosign+gitsign+sigstore/sigstore to https://github.com/sigstore/sigstore-go once it matures and has the capabilities we need.
  2. We can't mock some of the necessary behavior with the current libraries pertaining to looking up the tlog entry for the signature. These are marked internal at the moment, the sigstore-go library may also help us out here.
  3. The TAP-18 implementation depends on go-securesystemslib's sigstore-support branch that hasn't been merged into main and released.

Project Governance Documents

Hello gittuf!

The Linux Foundation has an initial set of documents for you to review that we think are useful for gittuf:

  1. Technical Charter Draft
  2. (NOT NEEDED) Contribution Agreement Draft (NOT NEEDED)
  3. (NOT NEEDED)Series Agreement Draft(NOT NEEDED)

Please review these materials and let us know if you have any questions. To give you some background on these materials:

Technical Project Charter Template

A technical charter is created for all new projects to define both the project operations and the IP policy. This document is used to set up an LLC entity, and this becomes the core governance of that LLC. We have proposed technical oversight for the project falls to a “Technical Steering Committee” made up of the project’s committers. At a later date the TSC is free to evolve how membership on the TSC is determined to accommodate project growth and the evolution of its governance.

If you like this doc as is let me know and we can adopt it, if you have changes then come to an agreement in together and then we can look at it too.

Project Contribution Agreement

In order to enable collaboration across organizations, the Linux Foundation and its project hosting entities hold project names, logos and key accounts (e.g., domain names, GitHub accounts, etc.) for the benefit of the project community. The way we do this is through the execution of the Project Contribution Agreement with the project’s founding organization or, in some cases, individual. While companies transferring project names and logos to us can continue use those names and logos in accordance with our trademark usage guidelines (please see https://lfprojects.org/policies/trademark-policy/), project names should not be used as part of a commercial product name. If you are currently using the name of the project as part of a product name, please let us know.

While the Project Contribution Agreement will ask about any trademark registrations, please note your organization may have common law trademark rights in a project name even if a registration has not been filed. Therefore, unless the project name has never been used publicly, we have Project Contribution Agreements signed even if there are no trademark registrations.

Series Agreement

You will note that the Technical Charter refers to the project as being organized as a “series” of LF Projects, LLC. LF Projects, LLC is one of our project hosting entities, and is a Delaware series limited liability company. Using LF Projects, LLC allows us to give a form of legal identity to projects. The document that gives existence to the project as a series of LF Projects, LLC, is the ‘Series Agreement’. The Series Agreement is a document signed by LF personnel, and no action is required on your part in creation of the series. We are including a copy of the Series Agreement in this packet because the Technical Charter will include references to the Series Agreement and the Series Manager (an LF employee who can act on behalf of the series).

Next Steps:

In terms of moving forward, the next steps are as follows:

  • Come to agreement on the finalized language for the Technical Charter.
  • We (OpenSSF) are in the process of upgrading and transitioning our GitHub to an Enterprise Account to https://github.com/openssf, so we want to wait on this to avoid duplicate efforts but eventually we can host your project there. In the mean time Add ‘thelinuxfoundation’ as an owner of the GitHub org
  • Send .svg of existing logo to [email protected]
  • We should prepare an announcement concerning the project launching with the OpenSSF [email protected]
  • Add the following as a website footer in tandem with an announcement:

Copyright © gittuf a Series of LF Projects, LLC
For web site terms of use, trademark policy and other project policies please see https://lfprojects.org/.

Should you have any questions, please do not hesitate to contact us. If you’d like to set up time to discuss these documents in further detail, please let us know a few suitable times.

Contacts

Your OpenSSF contact is Amanda Martin @hythloda on GitHub or [email protected] with any questions. You can book a time in my Calendar or invite me to any of your meetings to discuss the documents and I will generally rearrange my calendar to attend.

Project Formation

If you have any questions about the process of bringing your project to the LF, please reach out to Scott Nicholas, VP of Project Formation, and Todd Benzies, Senior Director of Project Formation, at [email protected].

It's good to review the FAQ on Project formation.

Thank you!

Use in-memory git repositories for tests

Where possible, we should use in-memory git repositories for tests instead of creating fs based repositories in /tmp. We currently do not do this for most of our tests because our git config parser shells out to the git binary. See: #18 (comment) for full discussion.

[Bug]: gittuf policy remote commands require a signing key

What happened?

The remote subcommands of gittuf policy inherit the persistent signing key flag that's required for other policy subcommands. This flag should not be required for push and pull operations as no new metadata signatures are issued.

Relevant log output

$ gittuf policy remote push origin
Error: required flag(s) "signing-key" not set
Usage:
  gittuf policy remote push <remote> [flags]

Flags:
  -h, --help   help for push

Global Flags:
  -k, --signing-key string   signing key to use to sign policy file

Code of Conduct

  • I agree to follow this project's Code of Conduct

Add consistent logging

gittuf needs a verbose mode with the actions it's performing logged in some manner. Currently, some workflows use logrus but this needs to be expanded.

Enable logging

gittuf's implementations should include verbose logging for the benefit of users. Actions within the internal/repository package in particular should log at various checkpoints what's happening. Further, the user should be able to see these logs via a --verbose flag they can invoke from the CLI.

Roadmap: Support source control attestations

gittuf must support storing and verifying source specific attestations. Some examples are code reviews, results of automated tests, and more.

Multi-Authorizations

Attestations can be used to verify policies that require multi-party sign off. For example, policies like "Alice must approve changes to file config.yml in the main branch but only Bob can push to main" requires both Alice and Bob to approve a change to config.yml in the main branch. Bob can sign the RSL entry making the change and Alice can sign the commit modifying the file, but in this case, Alice does not identify the branch for that commit. Instead, if Alice issues a review attestation explicitly for the main branch, we can verify the above policy. Also see: #68

SLSA Source Track

One of gittuf's aims is to support SLSA's under-development source track requirements. Any attestations defined through that effort can be used in gittuf for transparent, distributed verification of SLSA source requirements. Also see: slsa-framework/slsa#956

Distribute public keys for signed commits / tags

Currently, we distribute the keys used to sign states (this applies whether it's states as a whole or RSL described in #13). When specifying policies, we can currently say that some state of a ref was signed off on by the holder of a key recorded within gittuf. We want to also be able to say that a state was reached because of the holder of key K1 AND the commits introduced in this state change were signed by the holder of some key K2 (K1 and K2 may well be the same key).

There are a number of benefits to doing this.

  1. By supporting this, gittuf can bootstrap the keys used for Git signing. This is valuable for users whose threat model may not require finer access control policies or a reference state log (though they still get the latter for free).
  2. We largely tackle the observer problem. By not being able to define policies for the commit signers and instead relying on the signer of the state log entry, we misattribute authorship of commits that may be merged by another maintainer. With the feature described here, we can allow User A to merge changes into a protected branch (which they are authorized to do) where the changes are made by User B who is the sole authorized developer to change some file in the repository. The policy validation can now confirm the protected file was modified by the authorized user instead of inferring the modification was performed by User A who merely merged it into a protected branch.

cc @znewman01

[Bug]: Testing

What happened?

gittuf didn't behave like I wanted it to.

Relevant log output

stack trace goes here

Code of Conduct

  • I agree to follow this project's Code of Conduct

Add SPDX licence identifiers

As documented in ossf/tac#199, we need to add SPDX license identifiers to our source files. It's also one of the requirements for the next tier of the OpenSSF best practices badge.

Roadmap: Develop hash algorithm agility capabilities

Git uses the SHA-1 hash algorithm for its content addressed object store. Due to known weaknesses in SHA-1, there's work underway to support SHA-256. While the transition plan calls for backwards compatibility with SHA-1 repositories, this is currently not implemented. As a result, while experimental SHA-256 repositories can be created, an existing repository cannot make use of SHA-256. Also, such repositories are not supported on major forges like GitHub.

Key points for gittuf's implementation of hash algorithm agility:

  1. Support hash algorithm agility more generally. gittuf shouldn't just provide support for SHA-1 -> SHA-256 but must instead support other algorithms as well for potential future changes.
  2. Retain backwards compatibility with SHA-1 repositories so this feature can be enabled for existing repositories.
  3. When used with SHA-256, ensure compatibility with Git's own implementation of SHA-256 repositories. Then, a future transition can allow gittuf's identifiers to be used with Git's.

Current status: https://github.com/gittuf/gittuf/blob/main/docs/extensions/hash-algorithm-agility.md

Enable the use of `policy-staging` in root signing

#37 added basic root signing capabilities. There's currently a policy-staging namespace created for gittuf that is unused. Ideally, the root signing workflow (gittuf trust init) should allow for using this staging area for all root key holders to add their keys and then add their signatures.

[Bug]: Correct terminating flag behavior in delegation parsers

What happened?

This is an issue in the current main branch. The policy package walks the delegation graph in a few different contexts:

  1. FindPublicKeysForPath: used to apply policies for git refs / files etc
  2. Verify through findPublicKeysForPath: used to verify correct signers for each targets metadata

The first one has a fix in #168, where delegations are grouped by their metadata, and terminating behavior skips past the current group while preserving the overall delegations from other metadata. Once #168 is merged, we must evaluate the correct behavior for the delegated targets metadata.

Related: why do we have two different handlers for applying policies vs the expected signers for policy roles?

This is because a delegated metadata is expected to only be signed by the actors identified in the delegation to the role. OTOH, for identifying trusted verifiers for git ref / file policies, we use actors from each delegation that matches the namespace, so the authorized signers are pulled in by walking the delegation tree all the way to the leaf.

Relevant log output

N/A

Code of Conduct

  • I agree to follow this project's Code of Conduct

Roadmap: Developer teams and multiple hats

gittuf currently only enumerates actors using signing keys. To improve policy usability, two enhancements are in order:

  1. Support for teams: it must be possible to group actors together (team ios-devs is composed of [email protected], [email protected], etc.) and use the team definition in rules / delegations.
  2. Support for hats: the same actor may perform different actions wearing different hats. For example, an actor who's part of the dev team and the security team may have different privileges based on the hat they're currently wearing. gittuf currently does not support this perfectly outside of asking the same individual to use different keys for different hats, but it'd be neat to improve this aspect.

Decouple branch states from rule states

Currently, new valid states for branches (latest trusted commit, for example) is recorded in targets metadata. This issue discusses decoupling the records of branch states from the states that describe the access control policies for a repository. This has a number of advantages:

  1. It greatly reduces the footprint of TUF metadata
  2. It is simpler to maintain state linearity of the TUF metadata if the state is only tracking changes to access control policies--these are far rarer than commits in practice
  3. A separate record of branch states means that it can record states of branches not explicitly protected by the rules (ex: short lived feature branches) but are still vulnerable to branch state attacks
  4. (side effect) The CLI would improve as the user would no longer have to specify the role they're updating

Support gittuf-specific Git hooks

We need to define Git hooks for gittuf-specific actions that the gittuf command can apply to the specified repository. For this, we need to first define the operations that must be invoked via a Git hook, then define platform-specific hooks that get written to .git/hooks/. For example, a pre-push hook could be configured to create RSL entry for the ref being pushed. These hooks could be installed using a command like gittuf add-hooks.

Optionally generate a verification summary as an attestation

gittuf verify-ref (and other applicable workflows) must optionally generate a verification summary (when successful successful) in the form of an in-toto attestation. Among other things, the attestation must note the Git ref that was verified, the policies considered applicable, etc. gittuf could also allow for this attestation to be signed if the verifier presents a signing key.

See: https://github.com/in-toto/attestation/blob/main/spec/predicates/vsa.md and in-toto/attestation#295

Handle git-replace refs

Git has a feature to replace an instance of an object with another equivalent. This is tracked using the refspec in the refs/replace namespace. Note that these aren't synced automatically.

gittuf needs to be aware of this and handle it appropriately. This is best-effort as it depends entirely on if the verifier has the replace ref, but that's still fine because that copy of the repo isn't going to use the replacement either (barring TOCTOU changes).

https://www.git-scm.com/docs/git-replace

Add root key management tools

gittuf trust can currently only be initialized with a key. It has features to manage top level targets keys but none to add / remove root keys.

Related: #45

[Bug]: Unify signing mechanisms

What happened?

gittuf currently has two different signing workflows based on what's being signed. We use the user's default git configuration to sign commits / RSL entries etc, but a custom workflow for the policy metadata (where signatures are embedded in DSSE documents). The signerverifier package along with go-securesystemslib implements this at the moment.

The issues with having these be separate are as follows:

  1. metadata signing uses non standard keys right now, the custom sslib format (which is also being retired upstream)
  2. rules that authorize a user by their GPG or sigstore identity (for git commit signatures) cannot trivially be converted into a delegation because those signing methods currently can't be used to sign delegated policy metadata

I propose we unify the policy signing around git signing, because we want to preserve standard git signing workflows for compatibility with existing user workflows. So, we want to get to a place where the same gpg key / ssh key / sigstore identity from a user's git config can be used to sign gittuf policy metadata. FWIW, an ssh key used with git signing will likely align with upstream securesystemslib changes that retire the custom on-disk formats (solving point 1 above). We currently don't have prior art on signing DSSE with GPG but sigstore tools do sign in-toto attestations embedded in DSSE using OIDC. I think we can plug into those for sigstore and implement GPG + DSSE ourselves with some input from other securesystemslib / DSSE users.

cc @datosh

Relevant log output

No response

Code of Conduct

  • I agree to follow this project's Code of Conduct

Roadmap: Limiting read access to files stored in the repository

While the specification primarily focuses on who can write to a Git ref or some files stored in a repository, there are use cases for limiting the ability to read certain files. For example, a secret token can then be checked into a repository for use by CI builders.

The discussion for this began here: #23 (comment)

@adityasaky: I think we have some work to do on defining how read policies work first? For writes, we know exactly what we're verifying--commits/tags/other refs/RSL entries/files etc. For reads, it's less clear. Do we implement a gittuf reveal ? Does TUF metadata include the encrypted symmetric key that can be used to decrypt the secret in custom? Should custom always indicate the type of protection? There's also the matter of custom belongs in targets entries and not in delegation entries so this is a little complex. WDYT?

@JustinCappos:

I think we have some work to do on defining how read policies work first? For writes, we know exactly what we're verifying--commits/tags/other refs/RSL entries/files etc. For reads, it's less clear. Do we implement a gittuf reveal <secret file>?

I don't think we need a reveal command. I think that when you commit, etc. files you can decrypt things locally.

Does TUF metadata include the encrypted symmetric key that can be used to decrypt the secret in custom?

Yes, I think so. Although storing it other places may also be acceptable.

Should custom always indicate the type of protection? There's also the matter of custom belongs in targets entries and not in delegation entries so this is a little complex. WDYT?

Custom should likely indicate the type of protection. I think it needs to indicate the type of namespace, so this seems sensible.

The fact that delegation entries cannot include a custom field seems like an oversight in the TUF specification to me. We might see what others think...

@adityasaky:

I don't think we need a reveal command. I think that when you commit, etc. files you can decrypt things locally.

I'm a little wary here. It's too easy to git commit a decrypted file.

The fact that delegation entries cannot include a custom field seems like an oversight in the TUF specification to me. We might see what others think...

I'm experimenting with this here: https://github.com/adityasaky/gittuf/pull/27/files#diff-6f6158fdacef6b49dbe116bd6b52a72ab2a8cdd9cd0fe6cd7f531e86b163d185R87.

@JustinCappos:

I'm a little wary here. It's too easy to git commit a decrypted file.

It should be transparent to you. In other words, if Alice is committing foo and Bob can't read foo, Alice's commit encrypts the data first before adding it.

Obviously, this only works if Alice is using git-tuf and not git.

@adityasaky: Correct, but if Alice can read it and her gittuf client decrypts it, by default git assumes there's either a modification of the checked in file or that a new file has been created (if decrypted to a separate location). At that point, if Alice does a git add ., she may accidentally check in a secret. We may be able to do something like decrypting to a file in an ignored .gittuf-secret/ directory but the UX is still problematic for humans. It may be simpler when configuring a bot to use a secret.

@JustinCappos:
Okay, you bring up some interesting points.

So the options include:

  1. Masking files where read access isn't universal from git-tuf by .gitignore. This would also hide it from git...
  2. Copying read-only files to a new location, like you have in your example
  3. Living with the problem and calling misuse a 'user error'. This may not be as bad as it seems, because checking in a non-encrypted file to a git repo where there are access control rules, could trigger a repo running git-tuf scripts to reject the change.
  4. ???

I'd also like to mention that this all becomes more complex if Alice and Bob are sharing a repo (no read-only access) and later they want to add Charlie, but restrict what Charlie can read. I'm not sure how to think about this case, but the way I've been thinking about doing this with encryption doesn't seem to work to stop Charlie from reading the versions of files that existed before Charlie joined.

Add tests

gittuf currently does not have any unit tests. We should test all functionalities and especially our assumptions on how the underlying git binary works.

Ensure that git signing is viable

When using gittuf, we should make sure that git signing is viable before we touch anything in the repository - we don't want cases where we've initialized something and it turns out that we can't sign anything.

Possible bug: backslash handling in clone

#134 adds support for a simple clone function that clones a git repository and also fetches the repository's gittuf refs. The clone function infers the name of a local directory when one isn't provided, much like the default git clone command. It's possible that the current implementation of this directory name inferencing mishandles backslashes in the repository URL.

Add threat model to the design document

We need to move into the specification the threat model we've been working on in our research notes. Adding a threat model makes it easier to reason about gittuf's features. It is also a must-have for any security-focused project.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.