{"id":37188256,"url":"https://github.com/papito/ballot","last_synced_at":"2026-01-14T21:53:33.380Z","repository":{"id":40294481,"uuid":"146510807","full_name":"papito/ballot","owner":"papito","description":"Estimation poker tool for distributed teams","archived":false,"fork":false,"pushed_at":"2024-11-14T22:33:49.000Z","size":7136,"stargazers_count":6,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-14T23:28:55.813Z","etag":null,"topics":["agile","estimation","poker","scrum"],"latest_commit_sha":null,"homepage":"https://ballot.renegadeotter.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/papito.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":"2018-08-28T21:51:59.000Z","updated_at":"2024-11-14T22:33:52.000Z","dependencies_parsed_at":"2024-11-14T23:34:31.792Z","dependency_job_id":null,"html_url":"https://github.com/papito/ballot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/papito/ballot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/papito%2Fballot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/papito%2Fballot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/papito%2Fballot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/papito%2Fballot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/papito","download_url":"https://codeload.github.com/papito/ballot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/papito%2Fballot/sbom","scorecard":{"id":719973,"data":{"date":"2025-08-11","repo":{"name":"github.com/papito/ballot","commit":"a2fbd2569febca33c4c7527b85492fb447825ea5"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"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":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","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":"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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.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":"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":"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":"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":"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: MIT License: 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":"Pinned-Dependencies","score":2,"reason":"dependency not pinned by hash detected -- score normalized to 2","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/papito/ballot/main.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/papito/ballot/main.yml/master?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:2","Warn: containerImage not pinned by hash: Dockerfile:9","Warn: containerImage not pinned by hash: Dockerfile:15","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   3 containerImage dependencies pinned","Info:   1 out of   1 npmCommand 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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 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":0,"reason":"20 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-jr5f-v2jv-69x6","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-67mh-4wv8-2f99","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55","Warn: Project is vulnerable to: GHSA-vg6x-rcgg-rjx6","Warn: Project is vulnerable to: GHSA-x574-m823-4x7w","Warn: Project is vulnerable to: GHSA-4r4m-qw57-chr8","Warn: Project is vulnerable to: GHSA-xcj6-pq6g-qj4x","Warn: Project is vulnerable to: GHSA-356w-63v5-8wf4","Warn: Project is vulnerable to: GHSA-859w-5945-r5v3","Warn: Project is vulnerable to: GO-2022-0493 / GHSA-p782-xgp4-8hr8","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GO-2022-0603 / GHSA-hp87-p4gw-j4gq"],"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-22T11:00:02.696Z","repository_id":40294481,"created_at":"2025-08-22T11:00:02.696Z","updated_at":"2025-08-22T11:00:02.696Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28436234,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T21:32:52.117Z","status":"ssl_error","status_checked_at":"2026-01-14T21:32:33.442Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["agile","estimation","poker","scrum"],"created_at":"2026-01-14T21:53:32.666Z","updated_at":"2026-01-14T21:53:33.367Z","avatar_url":"https://github.com/papito.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ballot ![Publish Docker](https://github.com/papito/ballot/workflows/Publish%20Docker/badge.svg?branch=master)\n\nA web-based replacement for physical Scrum estimation cards, most useful for distributed teams. \n\n![Ballot](img/snapshot.png)\n\n## It's live\n[Try it here](https://ballot.renegadeotter.com/#/)\n\n## Features\n\n- A vote will end automatically when all votes are in\n- A vote can be finalized even if someone doesn't vote, because they are raiding the company fridge\n- If you are not a pig, you can join and observe an estimation session as a chicken\n\n## Stack:\n* Go HTTP server\n* React/Typescript UI\n* Redis for session state\n* Glue.js for WebSocket communication\n  \n## Installing and running\n\nWith DockerHub:\n\n    docker pull papito/ballot:latest\n    docker run -td -p8080:8080 --name ballot papito/ballot:latest\n\nWith external Redis:\n\n    docker pull papito/ballot:latest\n    docker run -td -p8080:8080 --name ballot -e\"REDIS_URL=...\" papito/ballot:latest\n\n## Development setup\n\n### Prerequisites\n  * Docker Compose\n  * Node 18\n  * Go 1.21\n\n### Starting up development\n\nIf you are special and don't have Make installed on your system, just\nlook at the Makefile and run the commands manually.\n\n#### Server\n\n```bash\n# Start the dockerized Redis (in a different window)\nmake db\n# Compile \u0026 run the Go server\nmake compile\nmake start\n```\n\n#### Client\n```bash\ncd ballot-ui\nmake install\nmake start\n```\n\n`IMPORTANT`: In development, the Go and the React apps run separately. \nThe server runs on port 8080 and the React app proxies requests to it. If you access\nthe app on port 8080 in development, you will be accessing the **build** (production) version of the React app.\n\n### Running server tests\n\n    make test\n\n### Running UI tests\n\n    cd ballot-ui\n    make test\n    # run a specific test\n    npx jest -t '\u003cpartial test name to match\u003e'\n\n\n### PRE-COMMIT HOOK\n\nIn `.git/hooks/pre-commit `:\n\n    #!/bin/sh\n    cd ballot-ui\n    make format\n    make lint\n\n\n### Build \u0026 run with Docker\n\n`docker build . -t ballot`\n`docker run -td -p8080:8080 --name ballot ballot`\n\nNote that this will install local Redis in the container, but that instance can be ignored if you configure Redis with environment variables (see below).\n\n### Environment variables\n\n  * HTTP_PORT - dictates which port the application will run on.\n  * REDIS_URL - Redis URL. If not provided, will connect to Docker Redis on the port 6380.\n  * ENV - context environment. `test`, `development`, or `production`. You can ignore this.\n\n\n### Connecting to Redis on Docker host\n\nBy default, the Docker container will have its own Redis instance, but you can have a persistent Redis running on Docker\nhost, by using the `--network=\"host\"` flag of Docker `run` command.\n\n## Redis schema\n\n#### ballot:user:{user_id} -\u003e Hash\n\nUser state for a session is stored here, and yes, this assumes that a user can only vote in one session.\n\n| Field       | Type                  |\n|-------------|-----------------------|\n| id          | UUID                  |\n| name        | String                |\n| estimate    | String                |\n| joined      | String (datetime)     |\n| is_observer | Flag                  |\n| is_admin    | Flag                  |\n\n`estimate` is an empty string by default.\n\n`joined` is used to sort users in a session by the order in which they had joined.\n\n#### ballot:session:{session_id}:users -\u003e Set[String]\n\nA set of users in this current session.\n\n#### ballot:session:{session_id}:observers -\u003e Set[String]\n\nA set of observers in this current session.\n\n#### ballot:session:{session_id}:vote_count -\u003e Int\n\nNumber of users in a session who cast a vote.\n\n#### ballot:session:{session_id}:tally -\u003e String\n\nFinal vote tally.\n\n#### ballot:session:{session_id}:voting -\u003e Int\n\n  * 0 - Not voting (idle before start, or vote finished)\n  * 1 - Voting\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpapito%2Fballot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpapito%2Fballot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpapito%2Fballot/lists"}