{"id":40141148,"url":"https://github.com/open-horizon/edge-sync-service","last_synced_at":"2026-01-19T14:30:39.089Z","repository":{"id":35085627,"uuid":"171522812","full_name":"open-horizon/edge-sync-service","owner":"open-horizon","description":"Cloud - Edge synchronization service (MMS)","archived":false,"fork":false,"pushed_at":"2025-08-19T13:39:05.000Z","size":1914,"stargazers_count":27,"open_issues_count":24,"forks_count":29,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-08-19T15:34:25.566Z","etag":null,"topics":["mms"],"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/open-horizon.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}},"created_at":"2019-02-19T17:58:47.000Z","updated_at":"2025-08-19T13:39:09.000Z","dependencies_parsed_at":"2022-09-09T09:30:42.429Z","dependency_job_id":"57f6ed53-c4de-4327-8491-821bb146aa34","html_url":"https://github.com/open-horizon/edge-sync-service","commit_stats":null,"previous_names":[],"tags_count":67,"template":false,"template_full_name":null,"purl":"pkg:github/open-horizon/edge-sync-service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-horizon%2Fedge-sync-service","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-horizon%2Fedge-sync-service/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-horizon%2Fedge-sync-service/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-horizon%2Fedge-sync-service/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/open-horizon","download_url":"https://codeload.github.com/open-horizon/edge-sync-service/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/open-horizon%2Fedge-sync-service/sbom","scorecard":{"id":708355,"data":{"date":"2025-08-11","repo":{"name":"github.com/open-horizon/edge-sync-service","commit":"b9815110e1b6f007bd4ac8ec94584f1e789e4b05"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.2,"checks":[{"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":"Code-Review","score":10,"reason":"all changesets reviewed","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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/pr-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":"Maintained","score":1,"reason":"2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1","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":"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":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/open-horizon/.github/SECURITY.md:1","Info: Found linked content: github.com/open-horizon/.github/SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: github.com/open-horizon/.github/SECURITY.md:1","Info: Found text in security policy: github.com/open-horizon/.github/SECURITY.md:1"],"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":"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/pr-test.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/open-horizon/edge-sync-service/pr-test.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pr-test.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/open-horizon/edge-sync-service/pr-test.yml/master?enable=pin","Warn: containerImage not pinned by hash: image/edge-sync-service-amd64/Dockerfile:1: pin your Docker image by updating docker.io/alpine:3.6 to docker.io/alpine:3.6@sha256:66790a2b79e1ea3e1dabac43990c54aca5d1ddf268d9a5a0285e4167c8b24475","Warn: containerImage not pinned by hash: image/edge-sync-service-arm64/Dockerfile:1: pin your Docker image by updating docker.io/multiarch/alpine:arm64-v3.6 to docker.io/multiarch/alpine:arm64-v3.6@sha256:42ca363c1594816db5d44e47e0c58dc1e842deb7e49940f6c35cd69c0d0a7c33","Warn: containerImage not pinned by hash: image/edge-sync-service-armhf/Dockerfile:1: pin your Docker image by updating docker.io/multiarch/alpine:armhf-v3.6 to docker.io/multiarch/alpine:armhf-v3.6@sha256:96e8850bde14bb4c31fb42025c05c459cb31de88dd1007d979529c1c4dce7ae9","Warn: goCommand not pinned by hash: get_dependencies.sh:5","Warn: goCommand not pinned by hash: get_dependencies.sh:10","Warn: goCommand not pinned by hash: get_dependencies.sh:15","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 goCommand dependencies pinned","Info:   0 out of   3 containerImage 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":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'","Warn: branch protection not enabled for branch 'v1.10'","Warn: branch protection not enabled for branch 'v1.9'","Warn: branch protection not enabled for branch 'v1.6'"],"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 30 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":1,"reason":"9 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2024-3321 / GHSA-v778-237x-gjrc","Warn: Project is vulnerable to: GO-2025-3487 / GHSA-hcg3-q754-cr77","Warn: Project is vulnerable to: GO-2023-1988 / GHSA-2wrh-6pvc-2jm9","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GHSA-qppj-fm5r-hxr3","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"],"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-22T07:24:59.096Z","repository_id":35085627,"created_at":"2025-08-22T07:24:59.096Z","updated_at":"2025-08-22T07:24:59.096Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28571769,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T12:50:50.164Z","status":"ssl_error","status_checked_at":"2026-01-19T12:50:42.704Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["mms"],"created_at":"2026-01-19T14:30:36.818Z","updated_at":"2026-01-19T14:30:39.082Z","avatar_url":"https://github.com/open-horizon.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# edge-sync-service\nCloud - Edge synchronization service\n\n[![Build Status](https://travis-ci.org/open-horizon/edge-sync-service.svg?branch=master)](https://travis-ci.org/open-horizon/edge-sync-service)\n![macOS](https://img.shields.io/badge/os-macOS-green.svg?style=flat)\n![Linux](https://img.shields.io/badge/os-linux-green.svg?style=flat)\n\n## Overview\nThe sync service is a management tool for Edge Computing. \nIt is designed to simplify applications that run on the edge by providing tools to synchronize objects between the cloud and the edge.  \nUsers of the sync service can create/update an object in the cloud and the object is then automatically propagated to the relevant edge nodes. \nSimilarly, an object can be updated on the edge and delivered to the cloud. \nExample use cases include synchronization of configuration, rules and actions, user preferences, AI models, monitoring statistics, deployment files, and more.\n\n### Sync service components\nThe sync service has two components:\n1. Cloud Sync Service (CSS) running in the cloud. The CSS supports multi-tenants, high availability, and load balancing.\n2. Edge Sync Service (ESS) running in edge nodes. Each ESS node has a Type and a unique ID.\n\nThe user application is also assumed to have an edge part and a cloud part.\nThe application interacts with the sync service (CSS and ESS) using REST calls.\nCommunication between the CSS and ESS nodes can be over MQTT or HTTP. \nThe sync service is designed to work with the Watson IoT Platform and perform all communication through it.\nDirect communication over HTTP/HTTPS or over an MQTT broker is also supported. \n\n![Figure](./component-overview.png)\n\nThe application provides the CSS/ESS an object that includes metadata, which defines the properties of the object, and optionally also binary data. \nThe object's metadata includes the destinations for the object. The sync service supports flexibly addressing which allows an object to be sent from the CSS to:\n1. A single ESS (using the ESS ID).\n2. All ESS nodes of a certain Type.\n3. Any group of ESS nodes.\n4. All ESS nodes.\n\nWhen an update for an object is received on the ESS/CSS the application is notified by the sync service. The application can then obtain and process the object.\nOnce the application is done processing the object it can mark it as consumed. The sync service allows users to view the delivery status of the object.  \n\n\n### Sync service main features \nThe following is a list of the main features provided by the sync service:\n1. The Sync Service handles all communication aspects between cloud and edge  \n    - Communication failures, edge nodes unavailable, limit on maximal message size, download resume, persistence accross restarts, and more.\n2. Simple flexible control over objects\n    - Create/Update/Read/Delete operations, version, persistence, expiration, activation time, delete on delivery, and more.\n3. Flexible object distribution \n    - Dynamic addressing, write/read directly to/from file system (file transfer), use link to data, and more. \n4. Automatic synchronization when edge node re/starts\n5. Tracking of delivery status\n    - Provides an indication of the delivery status of an object for each of its destinations. \n6. Tracking of edge nodes\n    - Allows users to view edge nodes\n7. A security model that enables the control over who can create/update/read/delete which objects and to what edge nodes these objects can be sent to.\n    - See the section [Security](#security)\n\n\n## Development\n\n### Prerequisites\n\n1. Go 1.10 or above\n\n### Setup\n\n1. Create a Go \"workspace\" directory named for example edge-sync-service (can be named anything)\n2. cd into the workspace directory\n3. Run:\n     1. `export GOPATH=$(pwd)`\n     2. `go get -d github.com/open-horizon/edge-sync-service`\n     3. `cd src/github.com/open-horizon/edge-sync-service`\n     4. `go mod tidy`\n     5. `go mod vendor`\n     6. `./get_dependencies.sh`\n\n### Build\n\nTo build the edge synch service, from the root of the workspace run:\n\n1. `export GOPATH=$(pwd)` (if not already done)\n2. `go install github.com/open-horizon/edge-sync-service/cmd/edge-sync-service`\n\nTo build the edge sync service container, from the root of the edge-sync-service repository run:\n\n1. `export GOPATH=\u003cworkspace root\u003e` (if not already done)\n2. `./buildContainer.sh \u003cplatform\u003e` (where platform is amd64, armhf, or arm64)\n\n**Notes:**\n1. The container will be tagged *open-horizon/edge-sync-service:latest*\n2. To build a container for armhf (arm-32), you need to:\n    1. Run the build script on a Linux box\n    2. On the Linux box that you are going to run the build script run:\n       1. `sudo apt-get install gcc-arm-linux-gnueabihf`\n       2. `docker run --rm --privileged multiarch/qemu-user-static:register --reset`\n3. To build a container for arm64, you need to:\n    1. Run the build script on a Linux box\n    2. On the Linux box that you are going to run the build script run:\n       1. `sudo apt-get install gcc-aarch64-linux-gnu`\n       2. `docker run --rm --privileged multiarch/qemu-user-static:register --reset`\n\n### Running\n\n#### Configuring\n\nSetup a pair of configuration files or use environment variables. See sync.conf for an example configuration\nfile. All of the appropriate environment variable names are listed in the configuration file. The use\nof a configuration file is **completely optional**. \n\n**Note:** If you are running both the cloud side and the edge side on the same box and are using environment variables\nto configure them, make sure the file /etc/edge-sync-service/sync.conf does **NOT** exist.\n\n##### SSL/TLS (access via HTTPS or connecting to broker via SSL/TLS)\n\nThe edge-sync-service when running on the \"edge\" will always only listen to requests using HTTPS. It automatically generates\nit's own self signed certificate and key pair. The CA certificate is */var/edge-sync-service/persist/sync/certs/cert.pem*.\n\nThe edge-sync-service when running on the \"cloud\" can listen either as HTTPS or as HTTP depending on whether or not the\nconfiguration properties **ServerCertificate** and **ServerKey** or the environment variables **SERVER_CERTIFICATE** and\n**SERVER_KEY** were set to the file names of the server certificate-key pair.\n\nTo connect to a MQTT broker that is using TLS and the server certtificate is signed with a CA that\nis not one of the well known CA's (i.e. self signed), you must provide the file containing the CA certificate using\nthe **MQTTCACertificate** configuration property or the **MQTT_CA_CERTIFICATE** environment variable.\n\n#### As the Cloud Sync Service\n\nTo run the cloud side of the edge-sync-service:\n\n1. `export GOPATH=\u003cworkspace root\u003e` (if not already done)\n2. In your configuration file make sure that *NodeType* is set to **CSS** or in the environment that\n**NODE_TYPE** is set to CSS.\n3. `$GOPATH/bin/edge-sync-service [-c \u003cconfig file name\u003e]`  (the -c option is only needed if you are using one)\n\nTo run the edge side of the edge-sync-service:\n\n1. `export GOPATH=\u003cworkspace root\u003e` (if not already done)\n2. In your configuration file make sure that *NodeType* is set to **ESS** or in the environment that\n**NODE_TYPE** is set to ESS.\n3. `$GOPATH/bin/edge-sync-service [-c \u003cconfig file name\u003e]`  (the -c option is only needed if you are using one)\n\n### Generate Swagger document\n\nTo generate the Swagger document for the Edge Synchronization Service you must:\n\n1. Install go-swagger by running:\n    1. `brew tap go-swagger/go-swagger`\n    2. `brew install go-swagger`\n2. From within your clone of the open-horizon/edge-sync-service repository, run:\n    - `swagger generate spec -o ./swagger.json -m -b ./cmd/edge-sync-service`\n\n**Note:** This will create an extra file in your clone of the repository. Do **NOT** commit the file.\n\n### View the generated Swagger document\n\nTo view the generated Swagger document:\n1. Run `$GOPATH/bin/edge-sync-service -swagger swagger.json`\n2. Open your browser and go to `http://\u003chost\u003e:\u003cport\u003e/swagger`.\n\nWhere *\u0026lt;host\u0026gt;* and *\u0026lt;port\u0026gt;* are the host and port your edge-sync-service is configured to listen on.\n\n### Samples\n\n[Sending and receiving files](./samples/send-receive-files/README.md)\n\n## Security\nThe Sync Service provides a secure infrastructure on which to synchronize objects from the cloud to the edge and from the edge to the cloud. It does this by typically requiring authentication and authorization to perform all tasks. Both objects and edge nodes, refered to as destinations, are protected when authentication is required.\n\n### Sync Service Authentication\n\nWhen authentication is required, all applications accessing the Sync Service via the Sync Service's RESTful API are required to provide an app key and app secret pair on all RESTful API calls.\n\n  - Each client SDK has an appropriate language dependent API call to set the app key and app secret for use by the client \"handle\" when making the RESTful API calls to the Sync Service server the client handle is connecting to.\n  - If one is not using one of the client SDKs and instead is making the RESTful API calls by one self, the app key and app secret must be sent as the username and password in a Basic Authorization header with each call.\n\nEdge Sync Service instances are also typically required to identify themselves when communicating with a Cloud Sync Service instance.\n\nThe exact form of the app key and app secret pair is dependent on how the Sync Service instance one is communicating with has been configured. The app key and app secret pair are used to determine and validate the user's identity. The user's identity includes their username, the organization they are part of, and the type of user they are. A user can be an organization admin, a regular user, or an edge node.\n\nIt should be noted that one can set up the Sync Service to not require authentication at all.\nThe default setup, while requiring authentication, makes most users organization admins.\nSuch a setup should **not** be used in a production setting.\n\n### Sync Service Authorization\n\nThe Sync Service protects objects by limiting access to object types. In addition it protects edge nodes by limiting access to destination types.\n\n#### Application Authorization\n\nIn order for an application to create, read, update, or delete an object in the Sync Service, it must have access to the object type of the object in question. The application does this by:\n\n1. Having authenticated with a user identity that is an organization admin in the object's organization.\n2. Having authenticated as a regular user, who's username is on an access control list for the object type in question.\n3. The access control list for the object type in question has been marked publically accessible.\n\nIn addition for an application to create an object on a Cloud Sync Service, it must have access to all of the destination types mentioned in the object's metadata. The application does this by:\n\n1. Having authenticated with a user identity that is an organization admin in the object's organization.\n2. Having authenticated as a regular user, who's username is on access control lists for the destination types in question.\n3. The access control lists for the destination types in question have been marked publically accessible.\n\n#### Edge Node Authorization\n\nSync Service instances running on Edge Nodes identify themselves when they communicate with Cloud Sync Service instances. This is done to prevent an Edge Sync Service instance from masquerading as some other destination.\nThe user identity used for an Edge Sync Service instance can be any one of the user identity types supported by the Sync Service. In particular, if the user identity is of:\n\n1. An edge node, the identity must match the destination type and destination ID of the Edge Sync Service instance.\n2. An organization admin, it must be an admin of the organization the edge node is part of.\n3. A regular user, that user's username must be on an access control list for the destination type of the Edge Sync Service instance.\n\n### Access Control Lists\n\nAccess control lists (ACLs) are used by the Sync Service to grant regular users both read and write access to object types and destination types within an organization. Users who are organization admins can add and remove users from ACLs. An ACL is automatically created when the first user's username is added to the ACL in question. An ACL is automatically deleted when the last user's username is removed from the ACL in question. Adding a username of asterisk (*) to an ACL allows any and all authenticated users within the organization access to object type or destination type in question.\n\nACLs are maintained using the appropriate Sync Service RESTful APIs. All of the Sync Service client SDKs provide language dependent APIs for these RESTful APIs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopen-horizon%2Fedge-sync-service","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopen-horizon%2Fedge-sync-service","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopen-horizon%2Fedge-sync-service/lists"}