n8n-local-sync 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- n8n_local_sync-0.1.0/.env.example +8 -0
- n8n_local_sync-0.1.0/.github/workflows/ci.yml +40 -0
- n8n_local_sync-0.1.0/.github/workflows/publish.yml +30 -0
- n8n_local_sync-0.1.0/.gitignore +56 -0
- n8n_local_sync-0.1.0/.pre-commit-hooks.yaml +7 -0
- n8n_local_sync-0.1.0/AGENTS.md +40 -0
- n8n_local_sync-0.1.0/LICENSE +21 -0
- n8n_local_sync-0.1.0/Makefile +24 -0
- n8n_local_sync-0.1.0/PKG-INFO +258 -0
- n8n_local_sync-0.1.0/README.md +217 -0
- n8n_local_sync-0.1.0/docker-compose.yml +19 -0
- n8n_local_sync-0.1.0/n8n/.keep +0 -0
- n8n_local_sync-0.1.0/pyproject.toml +46 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/__init__.py +2 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/api.py +93 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/cli.py +185 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/config.py +78 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/diff.py +130 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/export.py +91 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/import_.py +180 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/models.py +18 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/normalization.py +62 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/state.py +70 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/status.py +86 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/sync.py +118 -0
- n8n_local_sync-0.1.0/src/n8n_local_sync/validation.py +76 -0
- n8n_local_sync-0.1.0/tests/test_api.py +41 -0
- n8n_local_sync-0.1.0/tests/test_import.py +73 -0
- n8n_local_sync-0.1.0/tests/test_sync.py +70 -0
- n8n_local_sync-0.1.0/tests/test_validation.py +59 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# n8n API Key for authenticating with the n8n REST API
|
|
2
|
+
# You can generate this in your n8n instance under Settings > API
|
|
3
|
+
N8N_API_KEY=your_api_key_here
|
|
4
|
+
|
|
5
|
+
# (Optional) Base URL of your n8n instance.
|
|
6
|
+
# If provided, this overrides the URL specified in .n8n-sync.yaml.
|
|
7
|
+
# Example: http://localhost:5678
|
|
8
|
+
N8N_BASE_URL=
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ "main" ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ "main" ]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install hatchling pytest ruff build
|
|
28
|
+
pip install -e .[dev]
|
|
29
|
+
|
|
30
|
+
- name: Lint with ruff
|
|
31
|
+
run: |
|
|
32
|
+
ruff check src/ tests/
|
|
33
|
+
|
|
34
|
+
- name: Test with pytest
|
|
35
|
+
run: |
|
|
36
|
+
pytest tests/
|
|
37
|
+
|
|
38
|
+
- name: Build package
|
|
39
|
+
run: |
|
|
40
|
+
python -m build
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
build-and-publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
permissions:
|
|
11
|
+
id-token: write
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- name: Check out repository
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.10"
|
|
22
|
+
|
|
23
|
+
- name: Install build tool
|
|
24
|
+
run: pip install build
|
|
25
|
+
|
|
26
|
+
- name: Build package
|
|
27
|
+
run: python -m build
|
|
28
|
+
|
|
29
|
+
- name: Publish to PyPI
|
|
30
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# Environments
|
|
30
|
+
.env
|
|
31
|
+
.venv
|
|
32
|
+
env/
|
|
33
|
+
venv/
|
|
34
|
+
ENV/
|
|
35
|
+
env.bak/
|
|
36
|
+
venv.bak/
|
|
37
|
+
|
|
38
|
+
# Project specific
|
|
39
|
+
.n8n/
|
|
40
|
+
database.sqlite
|
|
41
|
+
volumes/
|
|
42
|
+
logs/
|
|
43
|
+
executions/
|
|
44
|
+
credentials/
|
|
45
|
+
|
|
46
|
+
# OS generated files
|
|
47
|
+
.DS_Store
|
|
48
|
+
.DS_Store?
|
|
49
|
+
._*
|
|
50
|
+
.Spotlight-V100
|
|
51
|
+
.Trashes
|
|
52
|
+
ehthumbs.db
|
|
53
|
+
Thumbs.db
|
|
54
|
+
|
|
55
|
+
n8n/*
|
|
56
|
+
!n8n/.keep
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
- id: validate-n8n-workflows
|
|
2
|
+
name: Validate n8n Workflows
|
|
3
|
+
description: Validates all n8n workflows in the directory to ensure schema correctness and prevents committing embedded secrets.
|
|
4
|
+
entry: n8n-sync validate
|
|
5
|
+
language: python
|
|
6
|
+
types: [json]
|
|
7
|
+
pass_filenames: false
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Instruções para Agentes de IA
|
|
2
|
+
|
|
3
|
+
Este documento (AGENTS.md) fornece diretrizes fundamentais para qualquer Agente de IA que venha a interagir com, dar manutenção ou expandir o código deste repositório.
|
|
4
|
+
|
|
5
|
+
## 1. Objetivo e Escopo
|
|
6
|
+
|
|
7
|
+
O `n8n-local-sync` é uma ferramenta CLI (Command Line Interface) open source.
|
|
8
|
+
* **Propósito:** Versionar, validar, exportar, importar e sincronizar workflows de n8n.
|
|
9
|
+
* **Não é:** Um servidor, uma aplicação web, ou um sistema distribuído complexo. Não faça overengineering.
|
|
10
|
+
* **Foco Inicial:** Interface CLI simples em Python que interaja com o Git e instâncias n8n.
|
|
11
|
+
|
|
12
|
+
## 2. Arquitetura e Integração com n8n
|
|
13
|
+
|
|
14
|
+
* O `n8n-local-sync` é uma ferramenta externa e independente. Não a embuta dentro da stack Docker do n8n de forma intrusiva (como um sidecar obrigatório).
|
|
15
|
+
* **Comunicação com n8n:** **Antes de utilizar qualquer comando, API, parâmetro ou comportamento específico do n8n, consulte a documentação oficial correspondente à versão fixada.** Utilize preferencialmente a **Public REST API** do n8n (introduzida na versão 0.164.0+) como meio de exportar/importar workflows, requerendo a passagem de API Keys (via `.env`), ao invés de hacks usando a CLI legada local.
|
|
16
|
+
* **Fonte da Verdade:** O Git (arquivos `.json` no repositório) é a única fonte da verdade. O banco de dados do n8n é considerado efêmero em relação aos workflows gerenciados pela ferramenta.
|
|
17
|
+
|
|
18
|
+
## 3. Padrões e Convenções de Código
|
|
19
|
+
|
|
20
|
+
* **Python:** Utilizar `Typer` para a CLI, `Pydantic` e `PyYAML` para as configurações e validações.
|
|
21
|
+
* **Scripts Shell:** Quando usar bash para automação ou CI, sempre inicie com `#!/usr/bin/env bash` seguido de `set -euo pipefail`. Use `ShellCheck`! Não use `eval`.
|
|
22
|
+
* **Packaging:** Utilize `pyproject.toml` (`hatchling`) para definir metadados do pacote e entrypoints CLI (`n8n-sync`).
|
|
23
|
+
|
|
24
|
+
## 4. Segurança (Criticamente Importante)
|
|
25
|
+
|
|
26
|
+
* Nunca adicione lógicas que cometam credenciais ou secrets no repositório.
|
|
27
|
+
* Arquivos `.env` devem sempre estar no `.gitignore`.
|
|
28
|
+
* A CLI deve alertar se tentar fazer parsing de um `.json` exportado que contenha credenciais embedded.
|
|
29
|
+
|
|
30
|
+
## 5. Testes e CI
|
|
31
|
+
|
|
32
|
+
* Python: Utilize `pytest`. Testes unitários para a configuração, parse do JSON e diffing.
|
|
33
|
+
* A integração contínua (GitHub Actions) deve rodar o Pytest e lint (Ruff) antes de autorizar publicações no PyPI.
|
|
34
|
+
|
|
35
|
+
## 6. Alterações na CLI
|
|
36
|
+
|
|
37
|
+
A CLI é a API primária da ferramenta para o usuário.
|
|
38
|
+
* Mantenha os comandos padronizados: `init`, `validate`, `export`, `import`, `sync`, `status`, `diff`.
|
|
39
|
+
* **Não invente comandos** que não estão planejados, a não ser que extremamente justificado por um roadmap.
|
|
40
|
+
* Garanta códigos de saída (`exit code`) apropriados: `0` para sucesso, não-`0` para erros, o que é fundamental para CI/CD e pre-commit hooks.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Daniel Dias Pereira
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.PHONY: setup test lint format docker-up docker-down build package
|
|
2
|
+
|
|
3
|
+
setup:
|
|
4
|
+
pip install -e ".[dev]"
|
|
5
|
+
|
|
6
|
+
test:
|
|
7
|
+
pytest tests/
|
|
8
|
+
|
|
9
|
+
lint:
|
|
10
|
+
ruff check src/ tests/
|
|
11
|
+
|
|
12
|
+
format:
|
|
13
|
+
ruff format src/ tests/
|
|
14
|
+
|
|
15
|
+
docker-up:
|
|
16
|
+
docker compose up -d
|
|
17
|
+
|
|
18
|
+
docker-down:
|
|
19
|
+
docker compose down
|
|
20
|
+
|
|
21
|
+
build:
|
|
22
|
+
hatch build
|
|
23
|
+
|
|
24
|
+
package: build
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: n8n-local-sync
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A CLI tool to version, validate, export, import, and sync workflows from self-hosted n8n instances using Git.
|
|
5
|
+
Author: DanielDPereira
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Daniel Dias Pereira
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Python: >=3.9
|
|
29
|
+
Requires-Dist: deepdiff>=6.7.1
|
|
30
|
+
Requires-Dist: httpx>=0.27.0
|
|
31
|
+
Requires-Dist: pydantic>=2.0
|
|
32
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
33
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
34
|
+
Requires-Dist: tenacity>=8.2.3
|
|
35
|
+
Requires-Dist: typer>=0.9.0
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: build>=1.0.3; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
<div align="center">
|
|
43
|
+
<h1>🚀 n8n-local-sync</h1>
|
|
44
|
+
<p><i>A lightweight, developer-first GitOps CLI for versioning, validating, and synchronizing n8n workflows.</i></p>
|
|
45
|
+
|
|
46
|
+
[](https://www.python.org/downloads/)
|
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## What is it?
|
|
53
|
+
|
|
54
|
+
**n8n-local-sync** bridges the gap between your [n8n](https://n8n.io/) instances and Git. By treating your n8n workflows as code, you can leverage standard software engineering practices—like version control, peer reviews, CI/CD, and automated deployments—for your automations.
|
|
55
|
+
|
|
56
|
+
## Why?
|
|
57
|
+
|
|
58
|
+
Managing n8n workflows through the UI is great for building, but challenging for lifecycle management.
|
|
59
|
+
Simple backups aren't enough. You need **version-controlled workflow management**.
|
|
60
|
+
|
|
61
|
+
With `n8n-local-sync`, you can:
|
|
62
|
+
- Track changes meaningfully using deterministic hashing.
|
|
63
|
+
- Review workflow changes in Git pull requests with clean diffs.
|
|
64
|
+
- Safely promote workflows across environments (dev → staging → prod) via CI/CD pipelines.
|
|
65
|
+
|
|
66
|
+
## Features
|
|
67
|
+
|
|
68
|
+
* 🔄 **Bidirectional Syncing:** Seamlessly pull (`sync` / `export`) and push (`import`) workflows using the official n8n REST API.
|
|
69
|
+
* 🧠 **Smart State Tracking:** Detects `LOCAL_MODIFIED`, `REMOTE_MODIFIED`, and `CONFLICT` states before destructive actions.
|
|
70
|
+
* 🛡️ **Validation & Security:** Catch invalid JSON structures and detect potential hardcoded secrets (heuristically).
|
|
71
|
+
* 🌲 **Git-Native:** Cleans workflow metadata and normalizes node order for deterministic, clean `git diff` outputs.
|
|
72
|
+
* 🧪 **Dry-Run Mode:** Simulate changes (`--dry-run`) across all destructive commands before applying them.
|
|
73
|
+
* 🏷️ **Tag Filtering:** Target specific environments or modules during export using the `--tag` flag.
|
|
74
|
+
* 🤖 **CI/CD Ready:** Configure your environment dynamically using `.env` files or environment variables.
|
|
75
|
+
|
|
76
|
+
## Architecture
|
|
77
|
+
|
|
78
|
+
```mermaid
|
|
79
|
+
graph TD
|
|
80
|
+
A[n8n Instance] <-->|REST API| B(n8n-local-sync)
|
|
81
|
+
B -->|Export / Pull| C[Local Git Repository]
|
|
82
|
+
B -->|Validate / Diff| C
|
|
83
|
+
C -->|Import / Push| B
|
|
84
|
+
C -->|Commit / Push| D[GitHub / GitLab]
|
|
85
|
+
D -->|CI/CD Actions| B
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
You can install `n8n-local-sync` directly from PyPI (once published) or from the source:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
pip install n8n-local-sync
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Quick Start
|
|
97
|
+
|
|
98
|
+
1. **Initialize and export:**
|
|
99
|
+
```bash
|
|
100
|
+
# Initialize project configuration
|
|
101
|
+
n8n-sync init
|
|
102
|
+
|
|
103
|
+
# Set your API credentials in the generated .env file
|
|
104
|
+
# Export workflows from your n8n instance
|
|
105
|
+
n8n-sync export
|
|
106
|
+
|
|
107
|
+
# Version control the results
|
|
108
|
+
git add n8n/workflows/ .n8n-sync.yaml
|
|
109
|
+
git commit -m "chore: initial workflow export"
|
|
110
|
+
git push
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
2. **Synchronize changes:**
|
|
114
|
+
```bash
|
|
115
|
+
# See what changed between local and remote
|
|
116
|
+
n8n-sync diff
|
|
117
|
+
n8n-sync status
|
|
118
|
+
|
|
119
|
+
# Pull remote changes safely (won't overwrite local modifications)
|
|
120
|
+
n8n-sync sync
|
|
121
|
+
|
|
122
|
+
# Push local changes back to n8n
|
|
123
|
+
n8n-sync push
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Configuration
|
|
127
|
+
|
|
128
|
+
Configuration resolves in the following priority:
|
|
129
|
+
1. **CLI Arguments** (`--force`, `--dry-run`)
|
|
130
|
+
2. **Environment Variables** (`N8N_API_KEY`, `N8N_BASE_URL`)
|
|
131
|
+
3. **Config File** (`.n8n-sync.yaml`)
|
|
132
|
+
|
|
133
|
+
> [!IMPORTANT]
|
|
134
|
+
> Never store your `N8N_API_KEY` in the `.n8n-sync.yaml` file. Always use environment variables or a `.env` file (which is ignored by Git).
|
|
135
|
+
|
|
136
|
+
### 🔄 Synching (Pulling) Remote Changes
|
|
137
|
+
|
|
138
|
+
Update your local repository with changes made directly in the n8n UI. The sync command evaluates the state of each workflow and avoids overwriting local modifications unless forced.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
n8n-sync sync # or n8n-sync pull
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**GitOps States Handled During Pull:**
|
|
145
|
+
- `UNCHANGED`: Skipped safely.
|
|
146
|
+
- `REMOTE_MODIFIED`: Remote changes are pulled, updating the local file.
|
|
147
|
+
- `LOCAL_MODIFIED`: Skipped with a warning (to protect local unpushed work). Use `--force` to overwrite local changes.
|
|
148
|
+
- `CONFLICT` (both changed): Skipped with a warning. Use `--force` to overwrite local with remote.
|
|
149
|
+
- `REMOTE_ONLY`: New remote workflows are pulled and saved locally.
|
|
150
|
+
- `LOCAL_ONLY`: Ignored by pull (use `push` to upload them).
|
|
151
|
+
|
|
152
|
+
*Note: Deletions are not automatically synced in either direction to prevent accidental data loss. If you delete a workflow in n8n, delete the local file manually.*
|
|
153
|
+
|
|
154
|
+
### 📤 Pushing Local Changes
|
|
155
|
+
|
|
156
|
+
Upload your local Git-versioned workflows to the remote n8n instance. Like pull, push is state-aware.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
n8n-sync import # or n8n-sync push
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**GitOps States Handled During Push:**
|
|
163
|
+
- `UNCHANGED`: Skipped safely.
|
|
164
|
+
- `LOCAL_MODIFIED`: Pushed to remote, updating the n8n workflow.
|
|
165
|
+
- `REMOTE_MODIFIED`: Skipped with a warning (to protect remote changes). Use `--force` to overwrite remote changes.
|
|
166
|
+
- `CONFLICT` (both changed): Skipped with a warning. Use `--force` to overwrite remote with local.
|
|
167
|
+
- `LOCAL_ONLY`: Creates a new workflow in n8n. The local file is automatically updated with the new ID assigned by n8n.
|
|
168
|
+
- `REMOTE_ONLY`: Ignored by push (use `pull` to download them).
|
|
169
|
+
|
|
170
|
+
## CLI Reference
|
|
171
|
+
|
|
172
|
+
- `n8n-sync init`: Initializes a project, creating `.n8n-sync.yaml` and `.env.example`.
|
|
173
|
+
- `n8n-sync sync` (alias `pull`): Safely synchronizes remote workflows to local files. Warns on conflicts.
|
|
174
|
+
- `n8n-sync import` (alias `push`): Pushes local workflows to the remote n8n instance.
|
|
175
|
+
- `n8n-sync export`: Forces an export of all (or tagged) remote workflows to local files.
|
|
176
|
+
- `n8n-sync diff`: Shows a granular, structural diff between local and remote workflows.
|
|
177
|
+
- `n8n-sync status`: Displays a summary table of workflow synchronization states (e.g., `LOCAL_MODIFIED`, `CONFLICT`).
|
|
178
|
+
- `n8n-sync validate`: Runs structural and security heuristic validations against local workflow JSON files.
|
|
179
|
+
|
|
180
|
+
**Common Flags:**
|
|
181
|
+
- `--dry-run`: Simulate operations without modifying local files or the remote n8n instance.
|
|
182
|
+
- `--force`: Force overwrite conflicts or local modifications during `sync`.
|
|
183
|
+
|
|
184
|
+
## Git Workflow
|
|
185
|
+
|
|
186
|
+
The typical GitOps flow looks like this:
|
|
187
|
+
|
|
188
|
+
1. Build a workflow in your Dev n8n instance.
|
|
189
|
+
2. Run `n8n-sync sync` to pull it down locally.
|
|
190
|
+
3. Review the structural changes using `git diff`.
|
|
191
|
+
4. Create a Pull Request.
|
|
192
|
+
5. On merge, a CI/CD pipeline runs `n8n-sync validate` and `n8n-sync push` to deploy the workflow to Production.
|
|
193
|
+
|
|
194
|
+
## Security
|
|
195
|
+
|
|
196
|
+
- **Heuristic Secret Scanning:** The `validate` command detects potential hardcoded secrets (`api_key`, `token`, `password`, etc.) in workflow nodes. *Note: This is a heuristic detection, not a strict guarantee.*
|
|
197
|
+
- **No Credentials Exposed:** The CLI is designed to never output API keys or authorization headers in error logs or standard output.
|
|
198
|
+
|
|
199
|
+
## n8n Compatibility
|
|
200
|
+
|
|
201
|
+
- **Supported/Tested Versions:** n8n `0.164.0` and above.
|
|
202
|
+
- **API Requirements:** Requires the n8n Public REST API (v1) to be enabled and accessible. Legacy CLI hacks are not supported.
|
|
203
|
+
|
|
204
|
+
## Development
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Clone the repository
|
|
208
|
+
git clone https://github.com/DanielDPereira/n8n-local-sync.git
|
|
209
|
+
cd n8n-local-sync
|
|
210
|
+
|
|
211
|
+
# Install with development dependencies
|
|
212
|
+
pip install -e .[dev]
|
|
213
|
+
|
|
214
|
+
# Run linting
|
|
215
|
+
ruff check src/ tests/
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
We bundle a pre-commit hook that runs `n8n-sync validate`.
|
|
219
|
+
```bash
|
|
220
|
+
pre-commit install
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Testing
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
# Run unit tests
|
|
227
|
+
pytest tests/
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Integration Testing
|
|
231
|
+
You can use the provided `docker-compose.yml` to spin up an ephemeral n8n instance for testing:
|
|
232
|
+
```bash
|
|
233
|
+
docker compose up -d
|
|
234
|
+
```
|
|
235
|
+
The instance will be available at `http://localhost:5678`.
|
|
236
|
+
|
|
237
|
+
## CI/CD
|
|
238
|
+
|
|
239
|
+
This project uses GitHub Actions for CI/CD:
|
|
240
|
+
- **CI**: Runs `pytest`, `ruff`, and `python -m build` on all PRs and pushes to `main`.
|
|
241
|
+
- **Publish**: Uses PyPI Trusted Publishing (OIDC) to securely publish new releases on tag.
|
|
242
|
+
|
|
243
|
+
## Roadmap
|
|
244
|
+
|
|
245
|
+
- [x] CLI foundation
|
|
246
|
+
- [x] Export/import
|
|
247
|
+
- [x] Git-friendly workflow files (canonicalization)
|
|
248
|
+
- [x] Validation (Heuristic secret scanning)
|
|
249
|
+
- [x] Diff & Status (State tracking)
|
|
250
|
+
- [x] Dry-run safe mode
|
|
251
|
+
- [x] CI and PyPI packaging readiness
|
|
252
|
+
- [ ] Integration test suite with Docker
|
|
253
|
+
- [ ] Multi-environment support (`--env prod`)
|
|
254
|
+
- [ ] Workflow promotion logic
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
This project is licensed under the MIT License.
|