Skip to content

Commit 98bb4dd

Browse files
stuartcmidigofrank
andauthored
Channels: HTTP proxy with observability for Lightning (#4419)
* Add Channels data layer: schemas, context, and migration * Add channel proxy plug with endpoint routing * Add channel proxy load testing and telemetry * Add Channels handler and observability pipeline * Add Channels source and sink authentication * Add Channels CRUD * Fix unique_constraint errors on channel name not showing up * Refactor ChannelProxyPlug headers and add request tracing * Add Channel LiveView UI: proxy URLs, icons, and polish * Add channel request search and logs page * Add channel logs infrastructure: tab bar, config, and History integration * Rename Weir dependency to Philter (now published on Hex) * Add Channels feature to CHANGELOG * Refactor channel proxy to use Philter's extra_headers/strip_headers Replace manual conn.req_headers mutation (Headers module) with Philter's purpose-built API. This fixes a security issue where source authentication headers (x-api-key for API auth, authorization for Basic auth) leaked through to the upstream sink. - Delete inner Headers module that mutated conn.req_headers - Add build_extra_headers/2 for proxy headers (x-forwarded-*, x-request-id, sink auth) - Add build_strip_headers/1 to remove source auth headers before forwarding - Add source_auth_types to SinkRequest struct, populated from channel config - Bump Philter to 0.2.0 for extra_headers/strip_headers support - Add 5 new tests: host rewrite regression, source auth stripping, passthrough * Update philter to 0.2.1 * Remove orphaned Headers test file The Headers module was extracted into Philter during the refactor, but this test file was left behind referencing the deleted module. --------- Co-authored-by: Midigo Frank <39288959+midigofrank@users.noreply.github.com> Co-authored-by: Frank Midigo <midigofrank@gmail.com>
1 parent bdec4c8 commit 98bb4dd

104 files changed

Lines changed: 9465 additions & 99 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.circleci/config.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,23 +171,24 @@ jobs:
171171
- run:
172172
name: "Check code formatting"
173173
command: |
174-
sudo -u lightning mix format --check-formatted || touch /tmp/lint_failed
174+
sudo -u lightning mix format --check-formatted || echo "format" >> /tmp/lint_failed
175175
- run:
176176
name: "Check code style with Credo"
177177
when: always
178178
command: |
179-
sudo -u lightning mix credo --strict --all || touch /tmp/lint_failed
179+
sudo -u lightning mix credo --strict --all || echo "credo" >> /tmp/lint_failed
180180
- run:
181181
name: "Check for security vulnerabilities"
182182
when: always
183183
command: |
184-
sudo -u lightning mix sobelow --threshold medium || touch /tmp/lint_failed
184+
sudo -u lightning mix sobelow --threshold medium || echo "sobelow" >> /tmp/lint_failed
185185
- run:
186186
name: "Verify all checks passed"
187187
when: always
188188
command: |
189189
if [ -f /tmp/lint_failed ]; then
190-
echo "One or more lint checks failed"
190+
echo "The following checks failed:"
191+
cat /tmp/lint_failed
191192
exit 1
192193
fi
193194

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ and this project adheres to
1717

1818
### Added
1919

20+
- Channels: a high-performance reverse proxy for forwarding authenticated
21+
requests between systems with full observability. Includes source/sink
22+
authentication, request/response logging, and a searchable history UI.
23+
[#4322](https://github.com/OpenFn/lightning/issues/4322)
2024
- Now saving "final output state" for runs, not just steps. (Important for
2125
workflows with multiple leaf nodes.)
2226
[#4485](https://github.com/OpenFn/lightning/issues/4485)

assets/js/hooks/index.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -760,15 +760,33 @@ export const Copy = {
760760
}
761761

762762
if (text) {
763-
const element = this.el;
764-
navigator.clipboard
765-
.writeText(text)
766-
.then(() => {
763+
if (navigator.clipboard?.writeText) {
764+
navigator.clipboard
765+
.writeText(text)
766+
.then(() => {
767+
this.showCopiedTooltip();
768+
})
769+
.catch(err => {
770+
console.error('Failed to copy text: ', err);
771+
});
772+
} else {
773+
// Fallback for insecure contexts (HTTP over non-localhost)
774+
const textarea = document.createElement('textarea');
775+
textarea.value = text;
776+
textarea.style.position = 'fixed';
777+
textarea.style.opacity = '0';
778+
document.body.appendChild(textarea);
779+
textarea.select();
780+
781+
try {
782+
document.execCommand('copy');
767783
this.showCopiedTooltip();
768-
})
769-
.catch(err => {
784+
} catch (err) {
770785
console.error('Failed to copy text: ', err);
771-
});
786+
} finally {
787+
document.body.removeChild(textarea);
788+
}
789+
}
772790
}
773791
});
774792
},
@@ -1014,6 +1032,7 @@ export const LocalTimeConverter = {
10141032
const textElement = this.el.querySelector('.datetime-text');
10151033
if (textElement && displayTime) {
10161034
textElement.textContent = displayTime;
1035+
textElement.className = 'datetime-text';
10171036
}
10181037
} catch (err) {
10191038
console.error('Failed to convert timestamp to display time:', err);

assets/tailwind.config.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,41 @@ export default {
125125
{ values }
126126
);
127127
}),
128+
// Embeds Lucide icons (https://lucide.dev) into your app.css bundle
129+
// Only a subset of icons are vendored. Add more SVGs to vendor/lucide/optimized/
130+
//
131+
plugin(function ({ matchComponents, theme }) {
132+
let iconsDir = path.join(
133+
__dirname,
134+
'./vendor/lucide/optimized/24/outline'
135+
);
136+
let values: Record<string, { name: string; fullPath: string }> = {};
137+
fs.readdirSync(iconsDir).forEach(file => {
138+
let name = path.basename(file, '.svg');
139+
values[name] = { name, fullPath: path.join(iconsDir, file) };
140+
});
141+
matchComponents(
142+
{
143+
lucide: ({ name, fullPath }) => {
144+
let content = fs
145+
.readFileSync(fullPath)
146+
.toString()
147+
.replace(/\r?\n|\r/g, '');
148+
return {
149+
[`--lucide-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
150+
'-webkit-mask': `var(--lucide-${name})`,
151+
mask: `var(--lucide-${name})`,
152+
'mask-repeat': 'no-repeat',
153+
'background-color': 'currentColor',
154+
'vertical-align': 'middle',
155+
display: 'inline-block',
156+
width: theme('spacing.6'),
157+
height: theme('spacing.6'),
158+
};
159+
},
160+
},
161+
{ values }
162+
);
163+
}),
128164
],
129165
} satisfies Config;

assets/vendor/lucide/LICENSE

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
ISC License
2+
3+
Copyright (c) for portions of Lucide are held by Cole Bemis 2013-2022 as part
4+
of Feather (MIT). All other copyright (c) for Lucide are held by Lucide
5+
Contributors 2022.
6+
7+
Permission to use, copy, modify, and/or distribute this software for any
8+
purpose with or without fee is hereby granted, provided that the above
9+
copyright notice and this permission notice appear in all copies.
10+
11+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)