Giter Club home page Giter Club logo

yaml-ui-editor's Introduction

yaml-ui-editor

YAML UI editing demo application with Git repository storage.

Overview

The purpose of this sample application is to demonstrate how to generate web user interfaces for editing externalized application configuration files in YAML format.

Examples of such files include Spring Boot external configuration files (application.yml and similar), and custom configuration for Ruby on Rails applications (via Rails::Application.config_for).

Motivation

Most applications have some externalized configuration. This configuration can be either technical, e.g., URLs for integration points, or they can be related to business rules that are evaluated by the application, such as limits, ranges, permitted values, etc.

The business-related configuration values are sometimes maintained and edited by people who may not be familiar with version control, or structured configuration file formats such as JSON, YAML, and properties files.

Some organizations handle this by adding a database in the runtime environment that is used for this configuration, and updates to the values are sometimes made directly to the production environment database. These updates are often validated by a process that is different from - and often less rigorous than - the typical production release process for an application. This can be a potential source of instability.

An alternative to the runtime configuration database is to apply the principle of hermetic releases, where binaries are released alongside the configuration files. One way to achieve this is to package configuration files into "configuration packages" that are deployed alongside the binary.

An example of a configuration package mechanism is a Kubernetes ConfigMap. Configuration files can be packaged into a ConfigMap, and the ConfigMap is referenced from the Kubernetes Pod specification.

To enable organizations to apply the same process for application changes as for configuration changes, the configuration files can be stored in version control alongside the application code.

Editing the configuration files can be facilitated by friendly user interfaces that can hide the configuration file structure and version control mechanisms from users who are unfamiliar with these.

This repository contains a sample application that shows how to build such an interface. It uses the example of YAML configuration files, with Git as the version control system.

Running the application

Edit the file src/main/resources/config/app.yml to specify the URL of the Git repository that holds the config files and schemas in the field git.repository.url.

You can also configure other properties in the same file, to customize the behavior of the application. For instance, you can specify which branch to check out from the Git repository, directories that contain the config files and schemas, the local directory to use for the repository clone, and more.

Run the application:

./gradlew bootRun

The application will be available on http://localhost:8080.

Using the application

You can log in as one of the test users pre-configured in the class WebSecurityConfig, e.g. alice, bob, or charlie. All users have the same password: password.

The available configs are shown on the horizontal top menu.

Try making a change to one of the configs, click Save, and then go to the Git repository to see the commit that was made by the application on behalf of the user.

Design

The application operates on two types of resources: config files and schemas. Config files are YAML files containing external application configuration. Schemas are JSON Schemas that define the structure of the config files. Each config file has a corresponding JSON schema.

The JSON schemas are used to generate web forms for viewing and editing values, and for validating the user-supplied data, both in-browser and on the server-side.

To allow JSON schemas to operate on the config, the config files are converted from YAML to JSON on the server-side, before they are sent to the browser client. This enables the application to use standard JSON Schema-based web user interface libraries to automatically generate the web forms.

Diagram showing flow of schemas and config data

When a user clicks Save, the browser client sends the form contents as JSON to the back-end. The server validates the input according to the JSON Schema, then converts the JSON to YAML, saves the YAML config to a file, and then commits and pushes that file to the Git repository.

Conflict resolution

This application deals with two Git repositories for config files and their schemas: the remote Git repository, and the local clone.

The remote Git repository is the primary repository, and it is likely hosted on a centralized Git host. If developers or operations staff have direct access to this repository, they could commit changes that conflict with edits made by users of this application.

Local repository conflicts can arise when two users of the application simultaneously make changes to the same config file.

This application employs different conflict resolution mechanisms for the two scenarios.

Local repository conflicts

When the UI requests a config file from the local Git repository for displaying a form, the response to the browser includes the latest Git commit ID for that file in the ETag HTTP header.

When the user - let's call them "user A" - submits the form, the request includes the same commit ID in the ETag HTTP request header. The application compares the commit ID in the request with the latest commit ID for that config file from the local Git repository. If another user - "user B" - submits a change to the same config file in between user A loading the form and submitting, the latest commit ID for that config file in the local Git repository will have changed. The change submitted by user A will not be saved, and user A will see an error message informing them that their submission failed due to concurrent changes.

This is implemented in the loadConfig() and saveConfig() methods in the files src/main/java/com/google/example/yamlui/config/ConfigController.java and src/main/java/com/google/example/yamlui/config/ConfigRepository.java, and in the JavaScript form submission event listener in the file src/main/resources/static/index.js.

Remote repository conflicts

For simultaneous edits in the remote Git repository, the application uses standard Git merge strategies. This is implemented in the pull() method in the file src/main/java/com/google/example/yamlui/git/GitClient.java.

The implementation uses the recursive merge strategy with the conflict option. Specifically, it performs the equivalent of:

git pull --ff --no-rebase --strategy recursive --strategy-option conflict [remote] [branch]

If the pull command results in conflicts, the application discards the submitted change and brings the its local Git clone in line with the remote Git repository. The implementation performs the equivalent of

git reset --hard remotes/origin/main

The intent of using this approach is to allow clean merges where non-conflicting edits are made to the same file, and to discard local changes if a commit has a conflict. The application then reloads the form with the latest values from the remote Git repository, and the user can attempt to make their changes again, if they still wish to do so.

Key dependencies

JSON Editor for the web user interface form generation from JSON Schemas. MIT license.

JGit for the Java implementation of Git. Eclipse Distribution License - v 1.0, an Open Source Initiative (OSI) Approved Open Source License by means of the 3-clause BSD License.

Spring Boot for the server-side implementation application framework. Apache 2.0 license.

Spring Security for the authentication and authorization. Apache 2.0 license.

networknt/json-schema-validator for server-side validation of config using JSON Schema. Apache 2.0 license.

Jackson for converting between JSON and YAML. Apache 2.0 license. This application uses Jackson instead of Gson because Jackson is already a dependency of networknt/json-schema-validator.

Alternative JSON Schema implementations

Numerous implementations of JSON Schema exist for a range of languages.

These implementations support various features, such as Web UI generation, validation, code generation, and more.

For Web UI generation, there are a number of implementations.

Disclaimer

This is not an officially supported Google product.

yaml-ui-editor's People

Contributors

halvards avatar

Stargazers

 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

yaml-ui-editor's Issues

Unauthorized Commits and Duplicate Commit Issue

Bug Report: Unauthorized Commits and Duplicate Commit Issue

Issue Description

Problem Summary

When configuring the application with GitHub credentials in the app.yml file, unauthorized commits can be pushed to the repository using the provided credentials. This leads to unexpected behavior, with both unauthorized and authorized commits appearing in the repository.

Steps to Reproduce

  1. Initial Configuration:

    • Clone the application repository.
    • Open the app.yml file.
    • Provide GitHub credentials under the git section as follows:
    git:
      credentials:
        # If _both_ username and password are provided, they will be used to authenticate to the remote
        # Git repository. Otherwise, the app uses the Git configuration on the host (e.g., stores and
        # helpers defined in `gitconfig`).
        username: <username>
        password: <password_that_i_use_to_log_to_my_github_account>
    
  2. Error Occurrence:

    • The application starts as expected
    • Make changes to the application configuration related to cars, fruits, or rules.
    • Attempt to save the changes.
    • An error occurred and the changes were not pushed to the repo.
  3. Error Description:
    An error occurs, preventing the changes from being saved. The error message should be described here:

console_error_1

console_error_2

  1. Investigation:
    After investigating the problem, it was discovered that the solution involves creating a token and using it in place of the actual password in the app.yml file:
    git:
      credentials:
        # If _both_ username and password are provided, they will be used to authenticate to the remote
        # Git repository. Otherwise, the app uses the Git configuration on the host (e.g., stores and
        # helpers defined in `gitconfig`).
        username: <username>
        password:  <token ie: ghp_A59PZtxtGIyE...>
    

Expected Behavior

When authorized GitHub credentials are provided in the app.yml file, the application should allow changes to be saved and committed to the repository without issues, and only the changes that have occurred when the authorized user (with the token) makes some changes to car, fruits or the rules.

Actual Behavior

Unauthorized commits are allowed to be pushed to the repository, along with the authorized commits. This results in both unauthorized and authorized changes appearing in the Git history.
As you can see here in my GitHub account commits:

Those changes were made when the unauthorized user made some changes, this commits isn't pushed to the repo directly.
unauthorized_commit

Those changes were made when the authorized user ( the one with the token) made some changes.
authorized_commit

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.