{"id":15634874,"url":"https://github.com/posener/gitfs","last_synced_at":"2025-09-10T04:42:26.665Z","repository":{"id":57486145,"uuid":"196074613","full_name":"posener/gitfs","owner":"posener","description":"A complete solution for static files in Go code","archived":false,"fork":false,"pushed_at":"2024-05-21T14:29:53.000Z","size":129,"stargazers_count":129,"open_issues_count":5,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-08T23:46:34.762Z","etag":null,"topics":["filesystem","go","golang","http","no-binary","static","static-files"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/posener.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-09T19:55:38.000Z","updated_at":"2025-04-01T16:04:41.000Z","dependencies_parsed_at":"2024-06-18T18:14:59.137Z","dependency_job_id":"2b278502-5bd0-42a9-baf9-5f0b688b0ab1","html_url":"https://github.com/posener/gitfs","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/posener/gitfs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fgitfs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fgitfs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fgitfs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fgitfs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/posener","download_url":"https://codeload.github.com/posener/gitfs/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/posener%2Fgitfs/sbom","scorecard":{"id":741582,"data":{"date":"2025-08-11","repo":{"name":"github.com/posener/gitfs","commit":"036be12fadb3bca2e577826d985e2d9ae66f448a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Code-Review","score":1,"reason":"Found 2/16 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/goreadme.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/goreadme.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/posener/gitfs/goreadme.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/goreadme.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/posener/gitfs/goreadme.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/posener/gitfs/test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/posener/gitfs/test.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/posener/gitfs/test.yml/master?enable=pin","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 22 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2025-3367 / GHSA-r9px-m959-cxf4","Warn: Project is vulnerable to: GO-2025-3368 / GHSA-v725-9546-7q7m","Warn: Project is vulnerable to: GO-2025-3488 / GHSA-6v2p-p543-phr9"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T17:36:15.404Z","repository_id":57486145,"created_at":"2025-08-22T17:36:15.405Z","updated_at":"2025-08-22T17:36:15.405Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274412848,"owners_count":25280199,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filesystem","go","golang","http","no-binary","static","static-files"],"created_at":"2024-10-03T10:58:17.962Z","updated_at":"2025-09-10T04:42:26.629Z","avatar_url":"https://github.com/posener.png","language":"Go","readme":"# gitfs\n\n[![codecov](https://codecov.io/gh/posener/gitfs/branch/master/graph/badge.svg)](https://codecov.io/gh/posener/gitfs)\n[![GoDoc](https://img.shields.io/badge/pkg.go.dev-doc-blue)](http://pkg.go.dev/github.com/posener/gitfs)\n\nPackage gitfs is a complete solution for static files in Go code.\n\nWhen Go code uses non-Go files, they are not packaged into the binary.\nThe common approach to the problem, as implemented by\n[go-bindata](https://github.com/kevinburke/go-bindata)\nis to convert all the required static files into Go code, which\neventually compiled into the binary.\n\nThis library takes a different approach, in which the static files are not\nrequired to be \"binary-packed\", and even no required to be in the same repository\nas the Go code. This package enables loading static content from a remote\ngit repository, or packing it to the binary if desired or loaded\nfrom local path for development process. The transition from remote repository\nto binary packed content, to local content is completely smooth.\n\n*The API is simple and minimalistic*. The `New` method returns a (sub)tree\nof a Git repository, represented by the standard `http.FileSystem` interface.\nThis object enables anything that is possible to do with a regular filesystem,\nsuch as opening a file or listing a directory.\nAdditionally, the [./fsutil](./fsutil) package provides enhancements over the `http.FileSystem`\nobject (They can work with any object that implements the interface) such\nas loading Go templates in the standard way, walking over the filesystem,\nand applying glob patterns on a filesystem.\n\nSupported features:\n\n* Loading of specific version/tag/branch.\n\n* For debug purposes, the files can be loaded from local path instead of the\nremote repository.\n\n* Files are loaded lazily by default or they can be preloaded if required.\n\n* Files can be packed to the Go binary using a command line tool.\n\n* This project is using the standard `http.FileSystem` interface.\n\n* In [./fsutil](./fsutil) there are some general useful tools around the\n`http.FileSystem` interace.\n\n## Usage\n\nTo create a filesystem using the `New` function, provide the Git\nproject with the pattern: `github.com/\u003cowner\u003e/\u003crepo\u003e(/\u003cpath\u003e)?(@\u003cref\u003e)?`.\nIf no `path` is specified, the root of the project will be used.\n`ref` can be any git branch using `heads/\u003cbranch name\u003e` or any\ngit tag using `tags/\u003ctag\u003e`. If the tag is of Semver format, the `tags/`\nprefix is not required. If no `ref` is specified, the default branch will\nbe used.\n\nIn the following example, the repository `github.com/x/y` at tag v1.2.3\nand internal path \"static\" is loaded:\n\n```go\nfs, err := gitfs.New(ctx, \"github.com/x/y/static@v1.2.3\")\n```\n\nThe variable `fs` implements the `http.FileSystem` interface.\nReading a file from the repository can be done using the `Open` method.\nThis function accepts a path, relative to the root of the defined\nfilesystem.\n\n```go\nf, err := fs.Open(\"index.html\")\n```\n\nThe `fs` variable can be used in anything that accept the standard interface.\nFor example, it can be used for serving static content using the standard\nlibrary:\n\n```go\nhttp.Handle(\"/\", http.FileServer(fs))\n```\n\n## Private Repositories\n\nWhen used with private github repository, the Github API calls should be\ninstrumented with the appropriate credentials. The credentials can be\npassed by providing an HTTP client.\n\nFor example, to use a Github Token from environnement variable `GITHUB_TOKEN`:\n\n```go\ntoken := os.Getenv(\"GITHUB_TOKEN\")\nclient := oauth2.NewClient(\n\tcontext.Background(),\n\toauth2.StaticTokenSource(\u0026oauth2.Token{AccessToken: token}))\nfs, err := gitfs.New(ctx, \"github.com/x/y\", gitfs.OptClient(client))\n```\n\n## Development\n\nFor quick development workflows, it is easier and faster to use local static\ncontent and not remote content that was pushed to a remote repository.\nThis is enabled by the `OptLocal` option. To use this option only in\nlocal development and not in production system, it can be used as follow:\n\n```go\nlocal := os.Getenv(\"LOCAL_DEBUG\")\nfs, err := gitfs.New(ctx, \"github.com/x/y\", gitfs.OptLocal(local))\n```\n\nIn this example, we stored the value for `OptLocal` in an environment\nvariable. As a result, when running the program with `LOCAL_DEBUG=.`\nlocal files will be used, while running without it will result in using\nthe remote files. (the value of the environment variable should point\nto any directory within the github project).\n\n## Binary Packing\n\nUsing gitfs does not mean that files are required to be remotely fetched.\nWhen binary packing of the files is needed, a command line tool can pack\nthem for you.\n\nTo get the tool run: `go get github.com/posener/gitfs/cmd/gitfs`.\n\nRunning the tool is by `gitfs \u003cpatterns\u003e`. This generates a `gitfs.go`\nfile in the current directory that contains all the used filesystems' data.\nThis will cause all `gitfs.New` calls to automatically use the packed data,\ninsted of fetching the data on runtime.\n\nBy default, a test will also be generated with the code. This test fails\nwhen the local files are modified without updating the binary content.\n\nUse binary-packing with `go generate`: To generate all filesystems used\nby a project add `//go:generate gitfs ./...` in the root of the project.\nTo generate only a specific filesystem add `//go:generate gitfs $GOFILE` in\nthe file it is being used.\n\nAn interesting anecdote is that gitfs command is using itself for generating\nits own templates.\n\n## Excluding files\n\nFiles exclusion can be done by including only specific files using a glob\npattern with `OptGlob` option, using the Glob options. This will affect\nboth local loading of files, remote loading and binary packing (may\nreduce binary size). For example:\n\n```go\nfs, err := gitfs.New(ctx,\n\t\"github.com/x/y/templates\",\n\tgitfs.OptGlob(\"*.gotmpl\", \"*/*.gotmpl\"))\n```\n\n## Sub Packages\n\n* [bin](./bin): Package bin is a proxy to the internal/binfs.Register function.\n\n* [cmd/gitfs](./cmd/gitfs): gitfs command line tool, for generating binary conetent of the used filesystems.\n\n* [examples/godoc](./examples/godoc): An example locally serves files from github.com/golang/go/doc.\n\n* [examples/templates](./examples/templates): An example that shows how gitfs helps using template files with Go code smoothly.\n\n* [fsutil](./fsutil): Package fsutil provides useful utility functions for http.FileSystem.\n\n## Examples\n\n### Fsutil\n\nThe [./fsutil](./fsutil) package is a collection of useful functions that can work with\nany `http.FileSystem` implementation.\nFor example, here we will use a function that loads go templates from the\nfilesystem.\n\n```golang\nctx := context.Background()\n\n// Open a git remote repository `posener/gitfs` in path `examples/templates`.\nfs, err := New(ctx, \"github.com/posener/gitfs/examples/templates\")\nif err != nil {\n    log.Fatalf(\"Failed initialize filesystem: %s\", err)\n}\n\n// Use util function that loads all templates according to a glob pattern.\ntmpls, err := fsutil.TmplParseGlob(fs, nil, \"*.gotmpl\")\nif err != nil {\n    log.Fatalf(\"Failed parsing templates: %s\", err)\n}\n\n// Execute the template and write to stdout.\ntmpls.ExecuteTemplate(os.Stdout, \"tmpl1.gotmpl\", \"Foo\")\n```\n\n Output:\n\n```\nHello, Foo\n```\n\n### Open\n\nWith gitfs you can open a remote git repository, and load any file,\nincluding non-go files.\nIn this example, the README.md file of a remote repository is loaded.\n\n```golang\nctx := context.Background()\n\n// The load path is of the form: github.com/\u003cowner\u003e/\u003crepo\u003e(/\u003cpath\u003e)?(@\u003cref\u003e)?.\n// `ref` can reference any git tag or branch. If github releases are in Semver format,\n// the `tags/` prefix is not needed in the `ref` part.\nfs, err := New(ctx, \"github.com/kelseyhightower/helloworld@3.0.0\")\nif err != nil {\n    log.Fatalf(\"Failed initialize filesystem: %s\", err)\n}\n\n// Open any file in the github repository, using the `Open` function. Both files\n// and directory can be opened. The content is not loaded until it is actually being\n// read. The content is loaded only once.\nf, err := fs.Open(\"README.md\")\nif err != nil {\n    log.Fatalf(\"Failed opening file: %s\", err)\n}\n\n// Copy the content to stdout.\nio.Copy(os.Stdout, f)\n```\n\n Output:\n\n```\n# helloworld\n```\n\n---\nReadme created from Go doc with [goreadme](https://github.com/posener/goreadme)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposener%2Fgitfs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fposener%2Fgitfs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fposener%2Fgitfs/lists"}