Giter VIP home page Giter VIP logo

harp's Introduction

License Go Report Card made-with-Go GitHub release Maintenance

Harp

Harp is for Harpocrates (Ancient Greek: Ἁρποκράτης) the god of silence, secrets and confidentiality in the Hellenistic religion. - Wikipedia

TL;DR.

Harp is a tool set to operate secret management by contract. The objective is to reduce the value centric management by handling secret data in a reproducible way by providing a technical stack to describe how your value is managed by contracts and pipelines. Furthermore, we know that naming thing is hard, as a consequence a secret could be consistently associated to a predictable secret identifier used as a key to refer to the secret value. Finally, the secret can hold additional metadata (ownership, rotation period, leak severity, etc.) which can be consumed during the pipeline executions.

These key/value associations (path ⇒ value) form a Bundle stored in an immutable file named a Container. This Container acts as a pivot format to allow Harp commands to communicate and create data management pipelines.

In addition to that, it provides a template engine used to generate various confidence values (password, passphrase, crypto keys, etc.) and allow more sophisticated rendering operations (configuration files, etc.).

Finally, it provides a SDK to allow developers to integrate Harp features in their products, and/or extend the Harp pipeline features by creating new plugins.

Visual overview

Visual overview

Why harp?

  • Secret management is in essence a collection of processes that must be auditable, executable and reproducible for infosec and operation requirements;
  • Secret provisioning must be designed with secret rotation as a day one task, due to the fact that secret data must be rotated periodically to keep its secret property;
  • Developers should negotiate secret value for the secret consumer they are currently developing, by the contract based on a path (reference to the secret) and a value specification (for code contract) without the knowledge of the final deployed value;
  • Secret Operators use different set of tools to achieve secret management operation which increases the error/secret exposure probability due to tool count involved in the process (incompatibility, changes, etc.);
  • Without a defined secret naming convention, the secret storage becomes difficult to handle in time (naming is hard) and secret naming could not be helped to get a consistent, reliable and flexible secret tree;
  • Secret storage backend can use various implementations in different environments and should be provisioned consistently.

Use cases

  • You want to have a single secret value and you are asking yourself how to generate a strong password - Harp has a template engine with secret value generation functions to allow you to generate such values.
  • You have thousands secrets to handle to deploy your platform/customers on multiple cloud providers with different secret storages - Harp will help you to define consistent secret provisioning bundles and pipelines.
  • You need a ephemeral secret storage to bootstrap your long term cloud secret storage - Harp will help you to create secret containers that can be consumed on deployment.
  • You want to migrate massively your secrets from one secret storage to another - Harp provides you a secret container to store these secrets while they are going to be distributed in other secret storage implementations.
  • You have to alter/modifiy a secret (rotation/deprecation/renewal) - Harp provides you a GitOps-able secret storage agnostic operation set, so that you can define a specification to describe how your secret operation is going to be applied offline on the secret container.

How does it work?

Secret management Pipeline

Like a Data pipeline but for secret

harp allows you to handle secrets using deterministic pipelines expressed using an atomic series of CLI operations applied to a commonly shared container immutable and standalone file system used to store secret collection (Bundle) generated from a template engine via user specification, or external secret value coming from files or external secret storage.

Pipelines

These pipelines use the immutable container file system as a data exchange protocol and could be extended for new input, intermediary operation or output via plugins created with the harp SDK.

Immutable transformation

Each applied transformation creates a container with transformed data inside. This will enforce container reproducibility by eliminating cumulative side effects applied to the same container.

The container handles for you the confidentiality and integrity protection applied to the secret collection stored inside and manipulated by copy during the pipeline execution.

What can I do?

New to harp, let's start with onboarding tutorial ! TL;DR - Features overview

Harp provides :

  • A methodology to design your secret management;
    • Secret naming convention (CSO);
    • A defined common language and complete processes to achieve secret management operations;
  • A SDK to create your own tools to orchestrate your secret management pipelines;
    • A container manipulation library exposed as github.com/elastic/harp/pkg/container;
    • A secret bundle specification to store and manipulate secrets exposed as github.com/elastic/harp/pkg/bundle;
    • An on-steroid template engine exposed as github.com/elastic/harp/pkg/template
    • A path name validation library exposed as github.com/elastic/harp/pkg/cso
  • A CLI for secret management implementation
    • CI/CD integration;
    • Based on human-readable definitions (YAML);
    • In order to create auditable and reproducible pipelines.
    • An extensible tool which can be enhanced via plugins.

And allows :

  • Bundle level operations
    • Create a bundle from scratch / template / JSON (more via plugins);
    • Generate a complete bundle using a YAML Descriptor (BundleTemplate) to describe secret and their usages;
    • Read value stored in the K/V virtual file system;
    • Update the K/V virtual file system;
    • Reproducible patch applied on immutable container (copy-on-write);
    • Import / Export to Vault.
  • Immutable container level operations
    • Seal / Unseal a container for integrity and confidentiality property conservation to enforce at-rest encryption (aes256-gcm96 or chacha20-poly1305);
    • Multiple identities sealing algorithm;

FAQ

  • Is it used internally at Elastic? - Yes. It is used to generate bootstrap secrets used to bootstrap the new region infrastructure components. #ChickenEggProblem

  • Harp is only supporting Vault? - No, it has been published with only vault support built-in, but it supports many other secret storage implementations via plugins.

  • What's the difference with Vault? - HashiCorp Vault is an encrypted highly available K/V store with advanced authorization engine, it doesn't handle secret provisioning for you. You can't ask Vault to generate secrets for your application and store them using a defined logic. Harp is filling this requirement.

License

harp artifacts and source code is released under Apache 2.0 Software License.

Homebrew install

Download a release or build from source.

For stable version

brew tap elastic/harp
brew install elastic/harp/harp

Build instructions

Download a release or build from source.

Clone repository

$ git clone [email protected]:elastic/harp.git
$ export HARP_REPOSITORY=$(pwd)/harp

Manual dev environment

Check your go version

Only last 2 minor versions of a major are supported.

Go 1.17/1.16

Harp is compiled with :

$ go version
go version go1.17.8 linux/amd64

Simple go version manager - https://github.com/stefanmaric/g

Go 1.18 (beta)

Go 1.18 compilation is enabled for testing purpose and golangci-lint looks to hang, so it has been disabled for the moment.

Install mage

Mage is an alternative to Make where language used is Go. You can install it using 2 different methods.

From source

# Install mage
git clone https://github.com/magefile/mage
cd mage
go run bootstrap.go

Daily

export PATH=$HARP_REPOSITORY/tools/bin:$PATH
# Build harp in bin folder
mage

With nix-shell

Install nix on your system, if not already installed.

$ sudo install -d -m755 -o $(id -u) -g $(id -g) /nix
$ curl -L https://nixos.org/nix/install | sh

More information? - https://nixos.wiki/wiki/Nix_Installation_Guide

$ cd $HARP_REPOSITORY
$ nix-shell

Bootstrap tools

# Go to tools submodule
cd $HARP_REPOSITORY/tools
# Resolve dependencies
go mod tidy
go mod vendor
# Pull tools sources, compile them and install executable in tools/bin
mage

Docker

For Tools

You have to build this image once before executing artifact pipelines.

mage docker:tools

Or you can download harp-tools from GitHub registry

# Standard usecase
$ docker pull ghcr.io/elastic/harp/harp-tools:latest
# FIPS compliant go toolchain
$ docker pull ghcr.io/elastic/harp/harp-tools-fips:latest

Check image integrity with cosign and the public key build/artifact/cosign.pub

cosign verify --key build/artifact/cosign.pub ghcr.io/elastic/harp/harp-tools:latest

Verification for ghcr.io/elastic/harp/harp-tools:latest --
The following checks were performed on each of these signatures:
  - The cosign claims were validated
  - The signatures were verified against the specified public key
  - Any certificates were verified against the Fulcio roots.

[{"critical":{"identity":{"docker-reference":"ghcr.io/elastic/harp/harp-tools"},"image":{"docker-manifest-digest":"sha256:1be31528e7b00c9e836479aadfdf49319f3b4d7916e705c43ffd0b14965763a8"},"type":"cosign container image signature"},"optional":{"ref":"40714fef947d018e6053991f5ddb54283f466b04","repo":"elastic/harp","workflow":"Build and push docker tools"}}]

For CLI

# or docker image [distroless:static, rootless, noshell]
mage docker:harp
# To execute in the container
docker run --rm -ti --read-only elastic/harp:<version>

Plugins

You can find more Harp feature extensions - https://github.com/elastic/harp-plugins

Community

Here is the list of external projects used as inspiration :

harp's People

Contributors

dependabot[bot] avatar fin09pcap avatar ksonney avatar zenithar 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

harp's Issues

[config] Config values are not honored with the command line flag

What version of Go are you using (go version)?

$ go version
go version go1.18.1 darwin/arm64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/fin09pcap/Library/Caches/go-build"
GOENV="/Users/fin09pcap/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/fin09pcap/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/fin09pcap/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/Users/fin09pcap/.go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/fin09pcap/.go/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.18.1"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/lp/ql182cbs1s55lq4nk5zwg1g00000gn/T/go-build3701245895=/tmp/go-build -gno-record-gcc-switches -fno-common"
GOROOT/bin/go version: go version go1.18.1 darwin/arm64
GOROOT/bin/go tool compile -V: compile version go1.18.1
uname -v: Darwin Kernel Version 21.4.0: Fri Mar 18 00:46:32 PDT 2022; root:xnu-8020.101.4~15/RELEASE_ARM64_T6000
ProductName:	macOS
ProductVersion:	12.3.1
BuildVersion:	21E258
lldb --version: lldb-1316.0.9.41
Apple Swift version 5.6 (swiftlang-5.6.0.323.62 clang-1316.0.20.8)

What version of Secret are you using (harp version)?

$ harp version
0.2.10 [main:2022-03-13T16:51:55Z] (Go: go1.17.7 darwin/arm64, Flags: defaults, Date: 2022-03-13T16:59:24Z)

What did you do?

harp config new > config.toml
$ harp config new > config.toml
$ cat config.toml

###############################
# Debug
###############################
[Debug]

  # allow debug mode
  enable = false

###############################
# Instrumentation
###############################
[Instrumentation]

  # Listen address for instrumentation server
  listen = ":5556"

  # Network class used for listen (tcp, tcp4, tcp6, unixsocket)
  network = "tcp"

  ###############################
  # Diagnotic Settings
  ###############################
  [Instrumentation.Diagnostic]

    # Enable diagnostic handlers
    enabled = false

    # Diagnostic settings
    [Instrumentation.Diagnostic.Config]

      [Instrumentation.Diagnostic.Config.GOPS]

        # Enable GOPS agent
        enabled = false

        # start a gops agent on specified URL. Ex: localhost:9999
        remoteDebugURL = ""

      [Instrumentation.Diagnostic.Config.PProf]

        # Enable PProf handler
        enabled = true

      [Instrumentation.Diagnostic.Config.ZPages]

        # Enable zPages handler
        enabled = true

  ###############################
  # Logs Settings
  ###############################
  [Instrumentation.Logs]

    # Log level: debug, info, warn, error, dpanic, panic, and fatal
    level = "warn"

Modify the debug settings to true.

What did you expect to see?

Debug output is enabled via the command line flag.

What did you see instead?

$ harp --config config.toml bundle dump --in test.bundle
Error: unknown flag: --config
Usage:
  harp bundle dump [flags]

Examples:
  # Dump a JSON representation of a Bundle object from STDIN
  harp bundle dump

  # Dump a JSON map containing package name as key and associated secret kv
  harp bundle dump --data-only

  # Dump a JSON map containing package name as key and associated metadata
  harp bundle dump --metadata-only

  # Dump all package paths as a list (useful for xargs usage)
  harp bundle dump --path-only

  # Dump a Bundle using a JMEFilter query
  harp bundle dump --query <jmesfilter query>

  # Dump a bundle content excluding the template used to generate
  harp bundle dump --skip-template

Flags:
      --content-only    Display content only (data-only alias)
      --data-only       Display data only
  -h, --help            help for dump
      --in string       Container input ('-' for stdin or filename)
      --metadata-only   Display metadata only
      --path-only       Display path only
      --query string    Specify a JMESPath query to format output
      --skip-template   Drop template from dump

harp to ruleset defined invalid schema

What version of Go are you using (go version)?

$ go version
go version go1.18.5 darwin/arm64

Does this issue reproduce with the latest release?

Yes.

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="/Users/fin09pcap/Library/Caches/go-build"
GOENV="/Users/fin09pcap/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/fin09pcap/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/fin09pcap/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/Users/fin09pcap/.go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/fin09pcap/.go/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.18.5"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/lp/ql182cbs1s55lq4nk5zwg1g00000gn/T/go-build2509289151=/tmp/go-build -gno-record-gcc-switches -fno-common"
GOROOT/bin/go version: go version go1.18.5 darwin/arm64
GOROOT/bin/go tool compile -V: compile version go1.18.5
uname -v: Darwin Kernel Version 21.6.0: Wed Aug 10 14:28:23 PDT 2022; root:xnu-8020.141.5~2/RELEASE_ARM64_T6000
ProductName:	macOS
ProductVersion:	12.5.1
BuildVersion:	21G83
lldb --version: lldb-1316.0.9.46
Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)

What version of Secret are you using (harp version)?

$ harp version
0.2.10 [main:2022-03-13T16:51:55Z] (Go: go1.17.7 darwin/arm64, Flags: defaults, Date: 2022-03-13T16:59:24Z)

What did you do?

{
  "secrets/foo/test": {
    "bar": "baz"
  }
}
harp from object --in test.json --out - | harp bundle dump --in - | jq .
{
  "packages": [
    {
      "name": "secrets/foo/test",
      "secrets": {
        "data": [
          {
            "key": "bar",
            "type": "string",
            "value": "ImJheiI="
          }
        ]
      }
    }
  ],
  "merkleTreeRoot": "qBiWpFkYKhkuBUXyIxxA1fSWCDXV8jHBJkgArt7D2dwqZ4mn/k7s2JbomfjzB/tNEI9CJXJ1n5cflhb96ao3lA=="
}
$ harp from object --in test.json --out - | harp to ruleset --in - --out -
api_version: harp.elastic.co/v1
kind: RuleSet
meta:
  description: Generated from bundle content
  name: qBiWpFkYKhkuBUXyIxxA1fSWCDXV8jHBJkgArt7D2dwqZ4mn_k7s2JbomfjzB_tNEI9CJXJ1n5cflhb96ao3lA
spec:
  rules:
  - constraints:
    - p.has_secret("bar")
    name: LINT-qBiWpF-1
    path: secrets/foo/test

$ harp from object --in test.json --out - | harp to ruleset --in - --out test.yaml
$ harp lint --schema RuleSet --in test.yaml
 - (root): Additional property api_version is not allowed
 - meta: owner is required
{"level":"fatal","@timestamp":"2022-08-24T23:58:02.156Z","@caller":"[email protected]/command.go:860","@message":"unable to execute task","@appName":"harp-lint","@version":"0.2.10","@revision":"2022-03-13T16:51:55Z","@appID":"TOqxliq4y8mCPAUEr2Us4jEE2MKKocTFfzGVpU6WuruCGtWGBNlS0Vk76Tzlp6dx","@fields":{"error":"ruleset not valid"}}
1. update test.yaml with apiVersion
$ harp lint --schema RuleSet --in test.yaml
 - meta: owner is required
{"level":"fatal","@timestamp":"2022-08-24T23:59:37.642Z","@caller":"[email protected]/command.go:860","@message":"unable to execute task","@appName":"harp-lint","@version":"0.2.10","@revision":"2022-03-13T16:51:55Z","@appID":"h4z0wUbv6OWyZuT4fT7t7JtG54n1pGSz4v5ooHUt6EVudmAdpibcoe7b8iNvzW1t","@fields":{"error":"ruleset not valid"}}

What did you expect to see?

When rendering the object it should have apiVersion and meta.owner defined for a valid schema.

What did you see instead?

See Above.

HCL2 to Vault Value Result

What version of Go are you using (go version)?

$ go version
go version go1.16 darwin/amd64

Does this issue reproduce with the latest release?

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/efreed/Library/Caches/go-build"
GOENV="/Users/efreed/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/Users/efreed/.gvm/pkgsets/go1.16/global/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/efreed/.gvm/pkgsets/go1.16/global"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/Users/efreed/.gvm/gos/go1.16"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/Users/efreed/.gvm/gos/go1.16/pkg/tool/darwin_amd64"
GOVCS=""
GOVERSION="go1.16"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/hb/cqz2kv_j6gv66cbzp0pr1zdh0000gn/T/go-build4035214422=/tmp/go-build -gno-record-gcc-switches -fno-common"
GOROOT/bin/go version: go version go1.16 darwin/amd64
GOROOT/bin/go tool compile -V: compile version go1.16
uname -v: Darwin Kernel Version 20.5.0: Sat May  8 05:10:33 PDT 2021; root:xnu-7195.121.3~9/RELEASE_X86_64
ProductName:	macOS
ProductVersion:	11.4
BuildVersion:	20F71
lldb --version: lldb-1205.0.28.2
Apple Swift version 5.4.2 (swiftlang-1205.0.28.2 clang-1205.0.19.57)

What version of Secret are you using (harp version)?

$ harp version
cmd/harp/v0.1.17-7-g89a4f9e [main:89a4f9e] (Go: go1.16.6, Flags: defaults, User: golang, Date: 2021-07-13T10:22:48Z)

What did you do?

spec.yml

apiVersion: harp.elastic.co/v1
kind: BundleTemplate
meta:
  name: "test-application-credentials"
  description: "Credentials for a test application"
  owner: [email protected]
spec:
  selector:
    quality: "{{ .Values.quality }}"
    platform: "ess"
    product: "test-application"
    version: "1.0.0"
  namespaces:
    platform:
      - region: "global"
        components:
          - name: "test-application"
            secrets:
              - suffix: "credentials"
                description: "testing credentials"
                template: |-
                  {
                    "cluster_username": "{{ .Values.variable.cluster_username }}"
                  }

main.tf

variable "cluster_username" {
  type    = string
  default = "myuser"
}
harp from bundle-template --in spec.yml  --out - --values main.tf:hcl2 --set quality=qa | harp bundle dump --in - --data-only | jq .
{
  "platform/qa/ess/global/test-application/credentials": {
    "cluster_username": "map[default:myuser type:${string}]"
  }
}
harp from bundle-template --in spec.yml  --out - --values main.tf:hcl2 --set quality=qa | harp to vault --in - --with-metadata

What did you expect to see?

I expected to see a key: cluster_username and value: myuser.

When trying to read vault from another terraform workspace data.vault_generic_secret..., its unable to handle map[default:myuser type:${string}].

What did you see instead?

Screen Shot 2021-07-21 at 10 39 01 AM

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.